Compare commits

...

2 Commits

Author SHA1 Message Date
HiBit
5fb7a4d9bc 登陆功能 2025-12-02 13:27:27 +08:00
HiBit
2b3125d826 1.代码提交 2025-11-29 14:05:30 +08:00
87 changed files with 2219 additions and 76 deletions

View File

@ -20,7 +20,7 @@ target 'SynthReel' do
pod 'YYCategories'
pod 'YYText'
pod 'Kingfisher'
pod 'SmartCodable'
pod 'SmartCodable','5.0.15'
pod 'Moya'
pod 'SVProgressHUD'
pod 'Toast'

View File

@ -140,6 +140,30 @@
3754ACEE2ED945A1009EBCAD /* Dictionary+SRAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACED2ED945A1009EBCAD /* Dictionary+SRAdd.swift */; };
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 */; };
3754AD022EDA8AF7009EBCAD /* SRLoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD012EDA8AF7009EBCAD /* SRLoginController.swift */; };
3754AD1A2EDD745A009EBCAD /* SRVideoLockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */; };
3754AD1C2EDD77BA009EBCAD /* SRVideoUnlockResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD1B2EDD77BA009EBCAD /* SRVideoUnlockResult.swift */; };
3754AD202EDD866F009EBCAD /* FacebookBasics in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD1F2EDD866F009EBCAD /* FacebookBasics */; };
3754AD222EDD866F009EBCAD /* FacebookCore in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD212EDD866F009EBCAD /* FacebookCore */; };
3754AD242EDD866F009EBCAD /* FacebookLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD232EDD866F009EBCAD /* FacebookLogin */; };
3754AD272EDD86FB009EBCAD /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD262EDD86FB009EBCAD /* FirebaseAnalytics */; };
3754AD292EDD86FB009EBCAD /* FirebaseAnalyticsCore in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD282EDD86FB009EBCAD /* FirebaseAnalyticsCore */; };
3754AD2B2EDD86FB009EBCAD /* FirebaseCore in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD2A2EDD86FB009EBCAD /* FirebaseCore */; };
3754AD2D2EDD86FB009EBCAD /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD2C2EDD86FB009EBCAD /* FirebaseCrashlytics */; };
3754AD2F2EDD86FB009EBCAD /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 3754AD2E2EDD86FB009EBCAD /* FirebaseMessaging */; };
3754AD312EDD939A009EBCAD /* SRUserLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD302EDD939A009EBCAD /* SRUserLoginView.swift */; };
3754AD332EDD96E0009EBCAD /* SRLoginButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD322EDD96E0009EBCAD /* SRLoginButtonView.swift */; };
3754AD362EDD9AA7009EBCAD /* SRLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD352EDD9AA7009EBCAD /* SRLogin.swift */; };
3754AD382EDD9B5D009EBCAD /* SRTokenModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD372EDD9B5D009EBCAD /* SRTokenModel.swift */; };
3754AD3A2EDD9BB1009EBCAD /* SRLogin+apple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754AD392EDD9BB1009EBCAD /* SRLogin+apple.swift */; };
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 */; };
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 */
@ -279,6 +303,23 @@
3754ACED2ED945A1009EBCAD /* Dictionary+SRAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+SRAdd.swift"; sourceTree = "<group>"; };
3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRFeedBackController.swift; sourceTree = "<group>"; };
3754ACF12ED975B9009EBCAD /* SRRewardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRRewardController.swift; sourceTree = "<group>"; };
3754ACF32ED98609009EBCAD /* SRCoinPackCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackCell.swift; sourceTree = "<group>"; };
3754ACF52ED9A2D4009EBCAD /* SRCoinPackTitleview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackTitleview.swift; sourceTree = "<group>"; };
3754ACF72ED9A32C009EBCAD /* SRCoinPackHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackHeaderView.swift; sourceTree = "<group>"; };
3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackModel.swift; sourceTree = "<group>"; };
3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackReceiveModel.swift; sourceTree = "<group>"; };
3754AD012EDA8AF7009EBCAD /* SRLoginController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRLoginController.swift; sourceTree = "<group>"; };
3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRVideoLockView.swift; sourceTree = "<group>"; };
3754AD1B2EDD77BA009EBCAD /* SRVideoUnlockResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRVideoUnlockResult.swift; sourceTree = "<group>"; };
3754AD1D2EDD84DD009EBCAD /* SynthReel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SynthReel.entitlements; sourceTree = "<group>"; };
3754AD302EDD939A009EBCAD /* SRUserLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserLoginView.swift; sourceTree = "<group>"; };
3754AD322EDD96E0009EBCAD /* SRLoginButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRLoginButtonView.swift; sourceTree = "<group>"; };
3754AD352EDD9AA7009EBCAD /* SRLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRLogin.swift; sourceTree = "<group>"; };
3754AD372EDD9B5D009EBCAD /* SRTokenModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRTokenModel.swift; sourceTree = "<group>"; };
3754AD392EDD9BB1009EBCAD /* SRLogin+apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRLogin+apple.swift"; sourceTree = "<group>"; };
3754AD3B2EDD9C01009EBCAD /* SRThirdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRThirdModel.swift; sourceTree = "<group>"; };
3754AD3D2EDD9C88009EBCAD /* SRLogin+FB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRLogin+FB.swift"; sourceTree = "<group>"; };
3754AEF72EDE94CD009EBCAD /* SRUserRewardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserRewardCell.swift; sourceTree = "<group>"; };
3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRShortHeaderView.swift; sourceTree = "<group>"; };
59DC746604B26E9FF802D317 /* Pods-SynthReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.debug.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.debug.xcconfig"; sourceTree = "<group>"; };
AA88214030574193B51DE563 /* Pods-SynthReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.release.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.release.xcconfig"; sourceTree = "<group>"; };
@ -290,9 +331,17 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3754AD272EDD86FB009EBCAD /* FirebaseAnalytics in Frameworks */,
03B1A84D2EC5DA43006C353F /* SnapKit in Frameworks */,
3754AD222EDD866F009EBCAD /* FacebookCore in Frameworks */,
3754AD242EDD866F009EBCAD /* FacebookLogin in Frameworks */,
3754AD202EDD866F009EBCAD /* FacebookBasics in Frameworks */,
03B1A84A2EC5CE37006C353F /* ESTabBarController in Frameworks */,
47BB39E2DD30787FA591F8EB /* Pods_SynthReel.framework in Frameworks */,
3754AD2D2EDD86FB009EBCAD /* FirebaseCrashlytics in Frameworks */,
3754AD2B2EDD86FB009EBCAD /* FirebaseCore in Frameworks */,
3754AD2F2EDD86FB009EBCAD /* FirebaseMessaging in Frameworks */,
3754AD292EDD86FB009EBCAD /* FirebaseAnalyticsCore in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -465,6 +514,7 @@
children = (
03B1A8EE2EC72C78006C353F /* SRShortModel.swift */,
03B1A9272ECC05B1006C353F /* SRShortDetailModel.swift */,
3754AD1B2EDD77BA009EBCAD /* SRVideoUnlockResult.swift */,
);
path = M;
sourceTree = "<group>";
@ -499,6 +549,7 @@
03B1A94D2ECD604B006C353F /* SREpSelectorCell.swift */,
3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */,
3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */,
3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */,
);
path = V;
sourceTree = "<group>";
@ -524,6 +575,7 @@
03E9A7C82EC47177000D1067 /* SynthReel */ = {
isa = PBXGroup;
children = (
3754AD1D2EDD84DD009EBCAD /* SynthReel.entitlements */,
03E9A7D02EC471D6000D1067 /* Delegate */,
03E9A7D22EC47204000D1067 /* Base */,
03E9A7D32EC4720F000D1067 /* Class */,
@ -573,6 +625,8 @@
03E9A7D32EC4720F000D1067 /* Class */ = {
isa = PBXGroup;
children = (
3754ACFF2EDA8A43009EBCAD /* Login */,
3754ACF92ED9A34E009EBCAD /* Store */,
3754ACDD2ED93C14009EBCAD /* Coinpack */,
370D2F0D2ED4532100571E77 /* User */,
03980F542ECEEC990006E317 /* MyShort */,
@ -585,6 +639,7 @@
03E9A7D42EC4764A000D1067 /* Libs */ = {
isa = PBXGroup;
children = (
3754AD342EDD9A8F009EBCAD /* SRLogin */,
3754ACD82ED83724009EBCAD /* FSPagerView */,
3754ACCF2ED81F2F009EBCAD /* Alert */,
3754ACC22ED6ED92009EBCAD /* Empty */,
@ -702,6 +757,10 @@
370D2F192ED45CCA00571E77 /* SRUserSettingCell.swift */,
370D2F242ED5807600571E77 /* SRAboutHeaderVIew.swift */,
370D2F262ED581BB00571E77 /* SRAboutCell.swift */,
3754ACF32ED98609009EBCAD /* SRCoinPackCell.swift */,
3754AD302EDD939A009EBCAD /* SRUserLoginView.swift */,
3754AD322EDD96E0009EBCAD /* SRLoginButtonView.swift */,
3754AEF72EDE94CD009EBCAD /* SRUserRewardCell.swift */,
);
path = view;
sourceTree = "<group>";
@ -759,6 +818,8 @@
3754ACDF2ED93C36009EBCAD /* view */ = {
isa = PBXGroup;
children = (
3754ACF52ED9A2D4009EBCAD /* SRCoinPackTitleview.swift */,
3754ACF72ED9A32C009EBCAD /* SRCoinPackHeaderView.swift */,
);
path = view;
sourceTree = "<group>";
@ -775,6 +836,51 @@
path = webview;
sourceTree = "<group>";
};
3754ACF92ED9A34E009EBCAD /* Store */ = {
isa = PBXGroup;
children = (
3754ACFA2ED9A359009EBCAD /* Model */,
);
path = Store;
sourceTree = "<group>";
};
3754ACFA2ED9A359009EBCAD /* Model */ = {
isa = PBXGroup;
children = (
3754ACFB2ED9A36C009EBCAD /* SRCoinsPackModel.swift */,
3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */,
);
path = Model;
sourceTree = "<group>";
};
3754ACFF2EDA8A43009EBCAD /* Login */ = {
isa = PBXGroup;
children = (
3754AD002EDA8ADD009EBCAD /* VC */,
);
path = Login;
sourceTree = "<group>";
};
3754AD002EDA8ADD009EBCAD /* VC */ = {
isa = PBXGroup;
children = (
3754AD012EDA8AF7009EBCAD /* SRLoginController.swift */,
);
path = VC;
sourceTree = "<group>";
};
3754AD342EDD9A8F009EBCAD /* SRLogin */ = {
isa = PBXGroup;
children = (
3754AD352EDD9AA7009EBCAD /* SRLogin.swift */,
3754AD372EDD9B5D009EBCAD /* SRTokenModel.swift */,
3754AD392EDD9BB1009EBCAD /* SRLogin+apple.swift */,
3754AD3B2EDD9C01009EBCAD /* SRThirdModel.swift */,
3754AD3D2EDD9C88009EBCAD /* SRLogin+FB.swift */,
);
path = SRLogin;
sourceTree = "<group>";
};
3779D05F2ECF1C8D006B1698 /* V */ = {
isa = PBXGroup;
children = (
@ -854,6 +960,8 @@
packageReferences = (
03B1A8482EC5CE37006C353F /* XCRemoteSwiftPackageReference "ESTabBarController" */,
03B1A84B2EC5DA43006C353F /* XCRemoteSwiftPackageReference "SnapKit" */,
3754AD1E2EDD866F009EBCAD /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */,
3754AD252EDD86FB009EBCAD /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 03E9A7A82EC4716A000D1067 /* Products */;
@ -929,6 +1037,7 @@
03B1A9402ECC45BA006C353F /* SRTableViewCell.swift in Sources */,
03E9A7EA2EC4995D000D1067 /* SRKeychain.swift in Sources */,
03E9A7D92EC47B90000D1067 /* SRNetworkReachableManager.swift in Sources */,
3754ACF82ED9A32C009EBCAD /* SRCoinPackHeaderView.swift in Sources */,
3754ACD72ED82774009EBCAD /* SRDetailRecommendCell.swift in Sources */,
370D2F2D2ED5AA9700571E77 /* SRViralHitCell.swift in Sources */,
03B1A8532EC5E12E006C353F /* UIScreen+SRAdd.swift in Sources */,
@ -959,6 +1068,7 @@
03B1A8E72EC7175D006C353F /* SRCategoryModel.swift in Sources */,
370D2F2F2ED5AB2500571E77 /* SRViralHitController.swift in Sources */,
3754ACDA2ED8374D009EBCAD /* SRPagerViewTransformer.swift in Sources */,
3754ACFE2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift in Sources */,
3754ACF22ED975B9009EBCAD /* SRRewardController.swift in Sources */,
03B1A94A2ECC79AB006C353F /* SREpSelectorView.swift in Sources */,
03B1A94E2ECD604B006C353F /* SREpSelectorCell.swift in Sources */,
@ -974,6 +1084,7 @@
03E9A7C92EC47177000D1067 /* AppDelegate.swift in Sources */,
03E9A7FA2EC56D03000D1067 /* String+SRAdd.swift in Sources */,
03B1A9192ECAF2E6006C353F /* SRHomePremiereNowView.swift in Sources */,
3754ACF42ED98609009EBCAD /* SRCoinPackCell.swift in Sources */,
03B1A92C2ECC0A7A006C353F /* SRShortDetailPlayerCell.swift in Sources */,
3754ACC42ED6EDA6009EBCAD /* SREmpty.swift in Sources */,
03B1A8392EC5C8D6006C353F /* SRHud.swift in Sources */,
@ -982,16 +1093,19 @@
370D2F092ED44A6D00571E77 /* SRListMenuCell.swift in Sources */,
03980F532ECEDEAB0006E317 /* SRRecommendPlayerControlView.swift in Sources */,
03B1A90F2ECAC768006C353F /* SRHomeBingeWorthyView.swift in Sources */,
3754ACFC2ED9A36C009EBCAD /* SRCoinsPackModel.swift in Sources */,
03B1A9072EC86656006C353F /* SRGradientView.swift in Sources */,
370D2F292ED58EC400571E77 /* SRTopChartsViewController.swift in Sources */,
370D2F1E2ED54C7F00571E77 /* SRHelpCenterController.swift in Sources */,
03E9A7CA2EC47177000D1067 /* SceneDelegate.swift in Sources */,
370D2F252ED5807600571E77 /* SRAboutHeaderVIew.swift in Sources */,
3754AD332EDD96E0009EBCAD /* SRLoginButtonView.swift in Sources */,
03B1A8402EC5CA37006C353F /* AppDelegate+Config.swift in Sources */,
03B1A9152ECAEE63006C353F /* SRHomeViralHitsCell.swift in Sources */,
03B1A8472EC5CBCF006C353F /* SRViewController.swift in Sources */,
370D2F052ED3FEE700571E77 /* SRHistoryCell.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 */,
03B1A8D82EC6D051006C353F /* SRCollectionView.swift in Sources */,
@ -1004,16 +1118,19 @@
03B1A83B2EC5C8E0006C353F /* SRToast.swift in Sources */,
03B1A9302ECC10D1006C353F /* SRSearchViewController.swift in Sources */,
03B1A8432EC5CB99006C353F /* SRTabBarController.swift in Sources */,
3754AD3E2EDD9C88009EBCAD /* SRLogin+FB.swift in Sources */,
03B1A8EF2EC72C78006C353F /* SRShortModel.swift in Sources */,
03B1A8ED2EC72C1F006C353F /* SRHomeModuleItem.swift in Sources */,
370D2F102ED4534500571E77 /* SRUserViewController.swift in Sources */,
03B1A9112ECAC927006C353F /* SRHomeBingeWorthyCell.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 */,
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 */,
3754ACD32ED82113009EBCAD /* SRGradientbutton.swift in Sources */,
@ -1025,8 +1142,10 @@
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 */,
03B1A8D52EC6CF37006C353F /* SRHomeChildViewController.swift in Sources */,
03B1A8F12EC72DD7006C353F /* SRHomeViewModel.swift in Sources */,
03E9A7FD2EC57658000D1067 /* SRUserApi.swift in Sources */,
@ -1034,8 +1153,12 @@
03B1A9012EC852B2006C353F /* SRHomeModuleView.swift in Sources */,
03E9A7EF2EC4A8AF000D1067 /* SRAccountManager.swift in Sources */,
03B1A8F52EC81277006C353F /* SRHomeBannerView.swift in Sources */,
3754AD312EDD939A009EBCAD /* SRUserLoginView.swift in Sources */,
3754AD1C2EDD77BA009EBCAD /* SRVideoUnlockResult.swift in Sources */,
3754ACDC2ED83F80009EBCAD /* SRHomeHistoryBottomView.swift in Sources */,
3754AEF82EDE94CD009EBCAD /* SRUserRewardCell.swift in Sources */,
03B1A9132ECAED04006C353F /* SRHomeViralHitsView.swift in Sources */,
3754AD382EDD9B5D009EBCAD /* SRTokenModel.swift in Sources */,
03B1A8DC2EC6D0EB006C353F /* SRHomeChildCell.swift in Sources */,
03B1A8552EC5E434006C353F /* UIFont+SRAdd.swift in Sources */,
3779D0612ECF1CB8006B1698 /* SRShortHeaderView.swift in Sources */,
@ -1052,6 +1175,7 @@
370D2F1C2ED4770800571E77 /* SRUserInfoModel.swift in Sources */,
03B1A93C2ECC406E006C353F /* SRHotSearchView.swift in Sources */,
03B1A8E32EC6F577006C353F /* SRHomeMenuCell.swift in Sources */,
3754AD362EDD9AA7009EBCAD /* SRLogin.swift in Sources */,
3754ACE12ED93C4D009EBCAD /* SRCoinPackController.swift in Sources */,
3754ACD52ED82722009EBCAD /* SRDetailRecommendview.swift in Sources */,
);
@ -1085,6 +1209,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = SynthReel/SynthReel.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
@ -1104,7 +1229,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.hbqinjiu.SynthReel;
PRODUCT_BUNDLE_IDENTIFIER = com.drama.hive;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
@ -1128,6 +1253,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = SynthReel/SynthReel.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
@ -1145,7 +1271,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.hbqinjiu.SynthReel;
PRODUCT_BUNDLE_IDENTIFIER = com.drama.hive;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
@ -1324,6 +1450,22 @@
minimumVersion = 5.7.1;
};
};
3754AD1E2EDD866F009EBCAD /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/facebook/facebook-ios-sdk";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 14.1.0;
};
};
3754AD252EDD86FB009EBCAD /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/firebase/firebase-ios-sdk";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 12.6.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@ -1337,6 +1479,46 @@
package = 03B1A84B2EC5DA43006C353F /* XCRemoteSwiftPackageReference "SnapKit" */;
productName = SnapKit;
};
3754AD1F2EDD866F009EBCAD /* FacebookBasics */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD1E2EDD866F009EBCAD /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
productName = FacebookBasics;
};
3754AD212EDD866F009EBCAD /* FacebookCore */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD1E2EDD866F009EBCAD /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
productName = FacebookCore;
};
3754AD232EDD866F009EBCAD /* FacebookLogin */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD1E2EDD866F009EBCAD /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
productName = FacebookLogin;
};
3754AD262EDD86FB009EBCAD /* FirebaseAnalytics */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD252EDD86FB009EBCAD /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseAnalytics;
};
3754AD282EDD86FB009EBCAD /* FirebaseAnalyticsCore */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD252EDD86FB009EBCAD /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseAnalyticsCore;
};
3754AD2A2EDD86FB009EBCAD /* FirebaseCore */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD252EDD86FB009EBCAD /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseCore;
};
3754AD2C2EDD86FB009EBCAD /* FirebaseCrashlytics */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD252EDD86FB009EBCAD /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseCrashlytics;
};
3754AD2E2EDD86FB009EBCAD /* FirebaseMessaging */ = {
isa = XCSwiftPackageProductDependency;
package = 3754AD252EDD86FB009EBCAD /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseMessaging;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 03E9A79F2EC4716A000D1067 /* Project object */;

View File

@ -1,6 +1,24 @@
{
"originHash" : "0e62262c59a183f44748a161870cc0f2b76e1b0e46f648559704e4be9de523b9",
"originHash" : "deb3ea9bc9f7ea16d149d6025086ec795e4f5fc740540ae9e5e8308e4e3e8aec",
"pins" : [
{
"identity" : "abseil-cpp-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
"version" : "1.2024072200.0"
}
},
{
"identity" : "app-check",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "61b85103a1aeed8218f17c794687781505fbbef5",
"version" : "11.2.0"
}
},
{
"identity" : "estabbarcontroller",
"kind" : "remoteSourceControl",
@ -10,6 +28,114 @@
"version" : "2.9.0"
}
},
{
"identity" : "facebook-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/facebook/facebook-ios-sdk",
"state" : {
"revision" : "c19607d535864533523d1f437c84035e5fb101cf",
"version" : "14.1.0"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "087bb95235f676c1a37e928769a5b6645dcbd325",
"version" : "12.6.0"
}
},
{
"identity" : "google-ads-on-device-conversion-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
"state" : {
"revision" : "35b601a60fbbea2de3ea461f604deaaa4d8bbd0c",
"version" : "3.2.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "c2d59acf17a8ba7ed80a763593c67c9c7c006ad1",
"version" : "12.5.0"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "617af071af9aa1d6a091d59a202910ac482128f9",
"version" : "10.1.0"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "60da361632d0de02786f709bdc0c4df340f7613e",
"version" : "8.1.0"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
"version" : "1.69.1"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "fb7f2740b1570d2f7599c6bb9531bf4fad6974b7",
"version" : "5.0.0"
}
},
{
"identity" : "interop-ios-for-google-sdks",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
"state" : {
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
"version" : "101.0.0"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
"version" : "1.22.5"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
"version" : "2.30910.0"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
"version" : "2.4.0"
}
},
{
"identity" : "snapkit",
"kind" : "remoteSourceControl",
@ -18,6 +144,15 @@
"revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4",
"version" : "5.7.1"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "c169a5744230951031770e27e475ff6eefe51f9d",
"version" : "1.33.3"
}
}
],
"version" : 3

View File

@ -89,6 +89,24 @@ struct SRShortApi {
}
}
static func requestCoinUnlockVideo(shortId: String?, videoId: String?) async -> SRVideoUnlockResult? {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/buy_video")
param.isToast = true
param.method = .post
param.parameters = [
"short_play_id": shortId ?? "",
"video_id": videoId ?? "0"
]
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRVideoUnlockResult>) in
continuation.resume(returning: response.data)
}
}
}
}

View File

@ -22,4 +22,93 @@ struct SRUserApi {
}
}
}
static func requestregister() async -> SRTokenModel? {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/customer/register")
param.method = .get
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRTokenModel>) in
continuation.resume(returning: response.data)
}
}
}
static func requestLeave() async {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/customer/leaveApp")
param.method = .post
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
continuation.resume()
}
}
}
static func requestEnterApp() async {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/customer/enterTheApp")
param.method = .post
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
continuation.resume()
}
}
}
static func requestStatOnLine() async {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/customer/onLine")
param.method = .post
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
continuation.resume()
}
}
}
static func requestStatApnsClick(id: String, title: String) async {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/message/sendReport")
param.method = .post
param.parameters = [
"message_id" : id,
"title" : title
]
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
continuation.resume()
}
}
}
static func requestUploadApnsDeviceToken(token: String) async {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/customer/onLine")
param.method = .post
param.parameters = [
"fcm_token": token
]
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
continuation.resume()
}
}
}
static func requestSignThirdLogin(model: SRThirdModel) async -> SRTokenModel? {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/customer/login")
param.method = .post
param.parameters = model.toDictionary()
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRTokenModel>) in
continuation.resume(returning: response.data)
}
}
}
static func requestLogout() async -> SRTokenModel? {
await withCheckedContinuation { continuation in
var param = SRNetwork.Parameters(path: "/customer/signout")
param.method = .post
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRTokenModel>) in
continuation.resume(returning: response.data)
}
}
}
}

View File

@ -30,7 +30,7 @@ extension SRNetwork {
var data: T?
var msg: String?
@SmartIgnored
@IgnoredKey
var rawData: Any?
var isSuccess: Bool {

View File

@ -19,7 +19,6 @@ let kSRFeedBackHomeWebUrl = SRCampaignWebURL + "/pages/leave/index"
let kSRFeedBackListWebUrl = SRCampaignWebURL + "/pages/leave/list"
///
let kSRFeedBackDetailWebUrl = SRCampaignWebURL + "/pages/leave/detail"
///
let kSRLogoutWebUrl = SRCampaignWebURL + "/pages/setting/logout"

View File

@ -15,13 +15,16 @@ class SRPanModalContentView: HWPanModalContentView {
var contentHeight = UIScreen.height * (2 / 3)
var bgImage: UIImage? = UIImage(named: "pan_bg_image_01")
///UI contentSize
func setNeedsLayoutUpdate() {
self.panModalSetNeedsLayoutUpdate()
}
lazy var bgImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "pan_bg_image_01"))
let imageView = UIImageView(image: bgImage)
return imageView
}()
@ -35,6 +38,18 @@ class SRPanModalContentView: HWPanModalContentView {
}
}
//
func updateBackgroundImage(_ img: UIImage?) {
self.bgImage = img
self.bgImageView.image = img
}
//
func updateContentHeight(_ height: CGFloat) {
self.contentHeight = height
self.panModalSetNeedsLayoutUpdate()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

View File

@ -8,23 +8,25 @@
import UIKit
class SRCoinPackController: UIViewController {
class SRCoinPackController: SRViewController {
lazy var topImageview = UIImageView.init(image: .topCoinPack)
override func viewDidLoad() {
super.viewDidLoad()
sr_setui()
self.navigationItem.title = "My Refills".localized
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
extension SRCoinPackController {
func sr_setui() {
view.addSubview(topImageview)
topImageview.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
}
}
}

View File

@ -0,0 +1,270 @@
//
// SRCoinPackHeaderView.swift
// SynthReel
//
// Created by CSGY on 2025/11/28.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
class SRCoinPackHeaderView: UIView {
var clickClaimButton: (() -> Void)?
var model: SRCoinsPackModel? {
didSet {
coinsView1.coins = model?.week_max_total
coinsView2.coins = model?.week_total
activeCountLabel.text = "\(model?.receive_count ?? 0)"
if let coin = model?.receive_coins, coin > 0 {
claimButton.isEnabled = true
} else {
claimButton.isEnabled = false
}
claimButton.setNeedsUpdateConfiguration()
}
}
private lazy var titleView: SRCoinPackTitleview = {
let view = SRCoinPackTitleview()
// view.dotColor = .C_5_DDF_5
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()
return view
}()
private lazy var coinsView1: CoinsView = {
let view = CoinsView()
view.title = "fableon_weekly_total".localized
view.coins = 0
return view
}()
private lazy var coinsView2: CoinsView = {
let view = CoinsView()
view.title = "fableon_claimable_coins".localized
view.coins = 0
return view
}()
private lazy var lineView1: UIView = {
let view = UIImageView(image: UIImage(named: "间隔线"))
return view
}()
private lazy var lineView2: UIView = {
let view = UIImageView(image: UIImage(named: "横间隔虚线"))
return view
}()
private lazy var activeCountTitleLabel: UILabel = {
let label = UILabel()
label.font = .font(ofSize: 12, weight: .regular)
label.textColor = .white.withAlphaComponent(0.5)
label.text = "fableon_active_refills".localized + ": "
return label
}()
private lazy var activeCountLabel: SRLabel = {
let label = SRLabel()
label.font = .font(ofSize: 12, weight: .medium)
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
}()
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
guard let self = self else { return }
guard let button = button as? SRGradientbutton 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: "coins_icon_03")!
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("fableon_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("fableon_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)
fa_setupLayout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SRCoinPackHeaderView {
private func fa_setupLayout() {
addSubview(titleView)
addSubview(coinsView1)
addSubview(coinsView2)
addSubview(lineView1)
addSubview(activeCountTitleLabel)
addSubview(activeCountLabel)
addSubview(claimButton)
addSubview(lineView2)
titleView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.top.equalToSuperview().offset(20)
}
coinsView1.snp.makeConstraints { make in
make.left.equalToSuperview().offset(28)
make.top.equalTo(titleView.snp.bottom).offset(23)
}
lineView1.snp.makeConstraints { make in
make.centerY.equalTo(coinsView1)
make.left.equalTo(coinsView1.snp.right).offset(18)
}
coinsView2.snp.makeConstraints { make in
make.centerY.equalTo(lineView1)
make.left.equalTo(lineView1.snp.right).offset(18)
}
activeCountTitleLabel.snp.makeConstraints { make in
make.left.equalTo(coinsView1)
make.top.equalTo(coinsView1.snp.bottom).offset(23)
}
activeCountLabel.snp.makeConstraints { make in
make.left.equalTo(activeCountTitleLabel.snp.right)
make.centerY.equalTo(activeCountTitleLabel)
}
claimButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(23)
make.centerX.equalToSuperview()
make.top.equalTo(activeCountTitleLabel.snp.bottom).offset(12)
make.height.equalTo(48)
make.bottom.equalToSuperview().offset(-16)
}
lineView2.snp.makeConstraints { make in
make.left.equalTo(claimButton)
make.right.equalTo(claimButton)
make.bottom.equalToSuperview()
}
}
}
extension SRCoinPackHeaderView {
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.withAlphaComponent(0.5)
return label
}()
private lazy var iconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "coins_icon_09"))
return imageView
}()
private lazy var coinsLabel: 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
}()
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.top.equalTo(titleLabel.snp.bottom).offset(4)
make.bottom.equalToSuperview()
}
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")
}
}
}

View File

@ -0,0 +1,92 @@
//
// 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")
}
}

View File

@ -0,0 +1,22 @@
//
// SRLoginController.swift
// SynthReel
//
// Created by CSGY on 2025/11/29.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
class SRLoginController: SRViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

View File

@ -32,7 +32,7 @@ class SRShortModel: NSObject, SmartCodable {
var category_name :String?
var category_id :String?
@SmartIgnored
@IgnoredKey
var cellHeight: CGFloat = 0

View File

@ -0,0 +1,25 @@
//
// SRVideoUnlockResult.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import SmartCodable
struct SRVideoUnlockResult: SmartCodable {
enum Status: String, SmartCaseDefaultable {
///
case jump = "jump"
///
case noPlay = "no_play"
///
case notEnough = "not_enough"
///
case success = "success"
}
var status: Status?
}

View File

@ -15,6 +15,7 @@ class SREpSelectorCell: UICollectionViewCell {
var model: SRVideoInfoModel? {
didSet {
numLabel.text = model?.episode
lockImageview.isHidden = !(model?.is_lock ?? true)
}
}
@ -48,6 +49,8 @@ class SREpSelectorCell: UICollectionViewCell {
return view
}()
lazy var lockImageview = UIImageView.init(image: .lock)
lazy var boderLayer: CAShapeLayer = {
let layer = CAShapeLayer()
return layer
@ -64,6 +67,7 @@ class SREpSelectorCell: UICollectionViewCell {
contentView.addSubview(boderView)
boderView.layer.addSublayer(boderLayer)
contentView.addSubview(numLabel)
contentView.addSubview(lockImageview)
numLabel.snp.makeConstraints { make in
make.center.equalToSuperview()
@ -73,6 +77,12 @@ class SREpSelectorCell: UICollectionViewCell {
make.edges.equalToSuperview()
}
lockImageview.snp.makeConstraints { make in
make.right.top.equalToSuperview().inset(4)
make.width.height.equalTo(12)
}
}

View File

@ -105,7 +105,6 @@ class SREpSelectorView: SRPanModalContentView {
override init(frame: CGRect) {
super.init(frame: frame)
sr_setupUI()
}
@ -189,6 +188,21 @@ extension SREpSelectorView: UICollectionViewDelegate, UICollectionViewDataSource
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let epList = self.model?.episodeList else { return }
if self.selectedIndex == indexPath.row { return }
let lastIndex = indexPath.row - 1
var lastIsLock = false
if lastIndex > 0 && lastIndex < epList.count {
let lastModel = epList[lastIndex]
lastIsLock = lastModel.is_lock ?? false
}
if lastIsLock {
SRToast.show(text: "buy_fail_toast_02".localized)
return
}
self.didSelected?(indexPath.row)
Task {
await self.dismiss(animated: true)

View File

@ -116,6 +116,7 @@ class SRShortDetailControlView: JXPlayerListControlView {
return button
}()
lazy var playerImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "play_icon_02"))
imageView.isHidden = true
@ -191,7 +192,7 @@ extension SRShortDetailControlView {
addSubview(epButton)
addSubview(collectButton)
addSubview(playerImageView)
progressBgView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.centerX.equalToSuperview()

View File

@ -23,16 +23,42 @@ class SRShortDetailPlayerCell: JXPlayerListCell {
return self.viewModel as? SRShortPlayerViewModel
}
var hasLastEpisodeUnlocked: Bool = false {
didSet {
self.lockView.hasLastEpisodeUnlocked = hasLastEpisodeUnlocked
}
}
private lazy var lockView: SRVideoLockView = {
let view = SRVideoLockView()
view.clickUnlockButton = { [weak self] in
Task {
await self?.sr_viewModel?.handleUnlockVideo()
}
}
return view
}()
override var model: Any? {
didSet {
let model = self.model as? SRVideoInfoModel
self.player.setPlayUrl(url: model?.video_url ?? "")
// self.lockView.isHidden = !(model?.is_lock ?? true)
// lockView.videoInfo = model
self.lockView.isHidden = !(model?.is_lock ?? true)
lockView.videoInfo = model
}
}
override init(frame: CGRect) {
super.init(frame: frame)
sr_setupLayout()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var shortModel: SRShortModel? {
didSet {
self.sr_controlView.shortModel = shortModel
@ -41,3 +67,16 @@ class SRShortDetailPlayerCell: JXPlayerListCell {
}
}
extension SRShortDetailPlayerCell {
private func sr_setupLayout() {
addSubview(lockView)
lockView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}

View File

@ -0,0 +1,120 @@
//
// SRVideoLockView.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
class SRVideoLockView: UIView {
var clickUnlockButton: (() -> Void)?
var adUnlockButton: (() -> Void)?
var videoInfo: SRVideoInfoModel? {
didSet {
unlockButton.setNeedsUpdateConfiguration()
}
}
var hasLastEpisodeUnlocked = false {
didSet {
unlockButton.setNeedsUpdateConfiguration()
}
}
lazy var unlockStackView: UIStackView = {
let stack = UIStackView()
stack.axis = .vertical
stack.spacing = 12
stack.distribution = .fillEqually
return stack
}()
private lazy var unlockButton: UIButton = {
var config = UIButton.Configuration.plain()
config.image = UIImage(named: "lock")
config.imagePadding = 6
// 使 UIImage
config.background.image = UIImage(named: "unlockButtonBg")
config.background.imageContentMode = .scaleToFill //
let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
guard let self = self else { return }
self.clickUnlockButton?()
}))
button.configurationUpdateHandler = { [weak self] button in
guard let self = self else { return }
let attributeContainer = AttributeContainer([
.font : UIFont.font(ofSize: 14, weight: .medium),
.foregroundColor : UIColor._51_D_4_FF
])
if hasLastEpisodeUnlocked {
button.configuration?.attributedTitle = .init("video_lock_tip_text".localized, attributes: attributeContainer)
} else {
button.configuration?.attributedTitle = .init("synthreel_unlocking_coins_notice".localizedReplace(text: "\(videoInfo?.coins ?? 0)"), attributes: attributeContainer)
}
}
return button
}()
private lazy var adlockButton: UIButton = {
var config = UIButton.Configuration.plain()
config.image = UIImage(named: "adlock")
config.imagePadding = 6
// 使 UIImage
config.background.image = UIImage(named: "unlockButtonBg")
config.background.imageContentMode = .scaleToFill //
let attr = AttributeContainer([
.font: UIFont.font(ofSize: 14, weight: .medium),
.foregroundColor: UIColor.white
])
config.attributedTitle = AttributedString("Watch 2ads to unlock".localized, attributes: attr)
let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
guard let self = self else { return }
self.adUnlockButton?()
}))
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = ._000000.withAlphaComponent(0.6)
sr_setupLayout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SRVideoLockView {
private func sr_setupLayout() {
addSubview(unlockStackView)
unlockStackView.addArrangedSubview(unlockButton)
unlockStackView.addArrangedSubview(adlockButton)
unlockStackView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(45)
make.right.equalToSuperview().offset(-45)
make.height.equalTo(43 * 2 + 30) // +
make.centerY.equalToSuperview() //
}
unlockButton.snp.makeConstraints { make in
make.height.equalTo(43)
}
adlockButton.snp.makeConstraints { make in
make.height.equalTo(43)
}
}
}

View File

@ -70,11 +70,31 @@ class SRDetailPlayerViewController: JXPlayerListViewController {
override func play() {
let videoInfo = self.viewModel.currentCell?.model as? SRVideoInfoModel
super.play()
Task {
await SRShortApi.requestCreatePlayHistory(shortId: videoInfo?.short_play_id, videoId: videoInfo?.short_play_video_id)
if videoInfo?.is_lock != true {
super.play()
Task {
await SRShortApi.requestCreatePlayHistory(shortId: videoInfo?.short_play_id, videoId: videoInfo?.short_play_video_id)
}
return
}
self.pause()
let myCoins = SRAccountManager.manager.userInfo?.totalCoins ?? 0
let lockCoins = videoInfo?.coins ?? 0
if myCoins < lockCoins, (self.sr_viewModel.currentCell as? SRShortDetailPlayerCell)?.hasLastEpisodeUnlocked != true {
// self.sr_viewModel.openRechargeView()
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
guard let self = self else { return }
if (self.sr_viewModel.currentCell as? SRShortDetailPlayerCell)?.hasLastEpisodeUnlocked != true {
Task {
await self.sr_viewModel.handleUnlockVideo()
}
}
}
}
}
@objc private func handleBackButton() {
@ -123,6 +143,13 @@ extension SRDetailPlayerViewController: JXPlayerListViewControllerDelegate, JXPl
let cell = self.dequeueReusableCell(withReuseIdentifier: "SRShortDetailPlayerCell", for: indexPath) as! SRShortDetailPlayerCell
cell.model = self.sr_viewModel.dataArr[indexPath.section].episodeList?[indexPath.row]
cell.shortModel = self.sr_viewModel.dataArr[indexPath.section].shortPlayInfo
let upRow = indexPath.row - 1
if upRow >= 0, let videoInfo = self.sr_viewModel.dataArr[indexPath.section].episodeList?[upRow], videoInfo.is_lock == true {
cell.hasLastEpisodeUnlocked = true
} else {
cell.hasLastEpisodeUnlocked = false
}
return cell
}

View File

@ -28,8 +28,9 @@ class SRShortPlayerViewModel: JXPlayerListViewModel {
nonisolated required init() {
super.init()
}
@MainActor
func requestShortDetail(indexPath: IndexPath? = nil) async -> Int? {
let (model, code, _) = await SRShortApi.requestShortDetail(shortId)
guard let model = model else { return code }
@ -41,27 +42,67 @@ class SRShortPlayerViewModel: JXPlayerListViewModel {
guard let self = self else { return }
var targetIndexPath = IndexPath(row: 0, section: 0)
if let indexPath = indexPath, indexPath.row < (model.episodeList?.count ?? 0) {
if let indexPath = indexPath,
indexPath.row < (model.episodeList?.count ?? 0) {
targetIndexPath = indexPath
} else if let videoInfo = model.video_info {
var row: Int?
model.episodeList?.enumerated().forEach {
if $1.short_play_video_id == videoInfo.short_play_video_id {
row = $0
}
}
if let row = row {
targetIndexPath = .init(row: row, section: 0)
if let row = model.episodeList?.firstIndex(where: {
$0.short_play_video_id == videoInfo.short_play_video_id
}) {
targetIndexPath = IndexPath(row: row, section: 0)
}
}
isShowRecommand = false
recommandTimer?.invalidate()
recommandTimer = nil
recommandTimer = Timer.scheduledTimer(timeInterval: 6, target: YYTextWeakProxy(target: self), selector: #selector(handleRecommandTimer), userInfo: nil, repeats: false)
recommandTimer = Timer.scheduledTimer(
timeInterval: 6,
target: YYTextWeakProxy(target: self),
selector: #selector(handleRecommandTimer),
userInfo: nil,
repeats: false
)
self.playerListVC?.scrollToItem(indexPath: targetIndexPath, animated: false)
}
return code
}
@MainActor
private func unlockVideo(completer: ((_ finish: Bool) -> Void)?) async {
guard let videoInfo = self.currentCell?.model as? SRVideoInfoModel else { return }
guard let shortPlayId = videoInfo.short_play_id else { return }
guard let videoId = videoInfo.short_play_video_id else { return }
let (model) = await SRShortApi.requestCoinUnlockVideo(shortId: shortPlayId,videoId: videoId)
guard let model = model else {
completer?(false)
return
}
switch model.status {
case .jump:
SRToast.show(text: "buy_fail_toast_02".localized)
case .noPlay:
SRToast.show(text: "buy_fail_toast_01".localized)
case .notEnough:
break
//广
// self.openRechargeView()
default: break
}
if model.status == .success {
Task {
await SRAccountManager.manager.updateUserInfo()
videoInfo.is_lock = false
completer?(true)
}
} else {
completer?(false)
}
}
}
@ -85,6 +126,21 @@ extension SRShortPlayerViewModel {
self.recommandList = model
}
@MainActor
func handleUnlockVideo() async {
await unlockVideo { [weak self] finish in
guard let self = self else { return }
if finish {
SRToast.show(text: "synthreel_success".localized)
self.playerListVC?.reloadData {
self.playerListVC?.play()
}
}
}
}
@objc private func handleRecommandTimer() {
self.isShowRecommand = true
}

View File

@ -0,0 +1,26 @@
//
// SRCoinsPackModel.swift
// SynthReel
//
// Created by CSGY on 2025/11/28.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import SmartCodable
struct SRCoinsPackModel: SmartCodable {
//
var receive_count: Int?
//
var week_total: Int?
//
var week_remaining_total: Int?
//
var week_max_total: Int?
//
var receive_coins: Int?
var receive_list: [SRCoinsPackReceiveModel]?
}

View File

@ -0,0 +1,26 @@
//
// SRCoinsPackReceiveModel.swift
// SynthReel
//
// Created by CSGY on 2025/11/28.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import SmartCodable
struct SRCoinsPackReceiveModel: SmartCodable {
var id: String?
var title: String?
//
var week_remaining_total: Int?
//
var receive_coins: Int?
//
var week_total: Int?
//
var week_max_total: Int?
//
var day_text: String?
}

View File

@ -17,14 +17,6 @@ class SRHelpCenterController: UIViewController {
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

View File

@ -15,16 +15,6 @@ class SRPrivacyController: UIViewController {
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

View File

@ -15,7 +15,4 @@ class SRRewardController: SRAppWebViewController {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

View File

@ -25,6 +25,9 @@ class SRUserViewController: SRViewController {
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()
@ -42,6 +45,8 @@ class SRUserViewController: SRViewController {
setDataArr()
// Do any additional setup after loading the view.
}
}
@ -59,26 +64,32 @@ extension SRUserViewController {
extension SRUserViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(indexPath.section == 0){
if indexPath.section == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "topcell", for: indexPath) as! SRUserTopCell
// cell.model = self.dataArr[indexPath.row];
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
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
if section == 0 || section == 1{
return 1
}
return self.dataArr.count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
return 3
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
@ -86,16 +97,22 @@ extension SRUserViewController: UICollectionViewDelegate, UICollectionViewDataSo
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = dataArr[indexPath.row]
if (model.type == .about){
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)
@ -123,6 +140,7 @@ 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)
}
}
@ -150,6 +168,7 @@ extension SRUserViewController {
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")),

View File

@ -17,12 +17,14 @@ struct SRUserSettingModel {
case privacyPolicy
case userAgreement
case visitWebsite
case login
case logout
// ///
// case consumptionRecords
case consumptionRecords
// ///
// case purchaseRecords
case purchaseRecords
// ///
// case rewardCoins
case rewardCoins
case deleteAccount
case language
}

View File

@ -0,0 +1,62 @@
//
// SRCoinPackCell.swift
// SynthReel
//
// Created by CSGY on 2025/11/28.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
class SRCoinPackCell: UICollectionViewCell {
lazy var bgImageView = UIImageView.init(image: UIImage(named: "userCoinCell"))
lazy var titleLabel : UILabel = {
let label = UILabel()
label.textColor = UIColor.B_5_DAE_6
label.font = .font(ofSize: 18, weight: .init(800))
label.text = "Daily reward ready !".localized
return label
}()
lazy var calimLabel : UILabel = {
let label = UILabel()
label.textColor = UIColor.white
label.font = .font(ofSize: 14, weight: .regular)
label.text = "Claim your rewards now".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 SRCoinPackCell {
func sr_setupUI() {
contentView.addSubview(bgImageView)
contentView.addSubview(titleLabel)
contentView.addSubview(calimLabel)
bgImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(16)
make.left.equalTo(84)
}
calimLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(4)
}
}
}

View File

@ -0,0 +1,66 @@
//
// SRLoginButtonView.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
class SRLoginButtonView: UIControl {
private let bgImageView = UIImageView()
private let iconView = UIImageView()
private lazy var titleLabel: SRLabel = {
let label = SRLabel()
label.font = .font(ofSize: 14, weight: .medium)
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)
return label
}()
private let arrowView = UIImageView(image: UIImage(named: "arrow_right_icon_01"))
init(icon: UIImage?, title: String, background: UIImage?) {
super.init(frame: .zero)
bgImageView.image = background
iconView.image = icon
titleLabel.text = title
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
addSubview(bgImageView)
addSubview(iconView)
addSubview(titleLabel)
addSubview(arrowView)
bgImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
iconView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(10)
make.centerY.equalToSuperview()
make.width.height.equalTo(20)
}
titleLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.centerX.equalToSuperview()
}
arrowView.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-16)
make.centerY.equalToSuperview()
make.width.equalTo(10)
make.height.equalTo(10)
}
}
}

View File

@ -0,0 +1,84 @@
//
// SRUserLoginView.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
class SRUserLoginView: SRPanModalContentView {
private let fbLoginView = SRLoginButtonView(
icon: UIImage(named: "fb_icon"),
title: "Login With Facebook".localized,
background: UIImage(named: "FacebookBg")
)
private let appleLoginView = SRLoginButtonView(
icon: UIImage(named: "apple_icon"),
title: "Login With Apple".localized,
background: UIImage(named: "appleBg")
)
override init(frame: CGRect) {
super.init(frame: frame)
sr_setupUI()
self.updateContentHeight(246)
self.updateBackgroundImage(.loginBg)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SRUserLoginView {
func sr_setupUI() {
addSubview(fbLoginView)
addSubview(appleLoginView)
fbLoginView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(35)
make.left.equalToSuperview().offset(48)
make.right.equalToSuperview().offset(-48)
make.height.equalTo(48)
}
appleLoginView.snp.makeConstraints { make in
make.top.equalTo(fbLoginView.snp.bottom).offset(20)
make.left.right.height.equalTo(fbLoginView)
}
//
fbLoginView.addTarget(self, action: #selector(tapFB), for: .touchUpInside)
appleLoginView.addTarget(self, action: #selector(tapApple), for: .touchUpInside)
}
@objc func tapFB() {
self.login(type: .faceBook)
}
@objc func tapApple() {
self.login(type: .apple)
}
private func login(type: SRLogin.LoginType) {
SRHud.show()
SRLogin.manager.thirdLogin(type: type, presentingViewController: nil) { [weak self] isFinish in
SRHud.dismiss()
guard let self = self else { return }
if isFinish {
Task {
await self.dismiss(animated: true)
}
}
}
}
}

View File

@ -0,0 +1,13 @@
//
// SRUserRewardCell.swift
// SynthReel
//
// Created by CSGY on 2025/12/2.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
class SRUserRewardCell: UICollectionViewCell {
}

View File

@ -52,7 +52,7 @@ extension SRUserSettingCell {
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(iconImage.snp_rightMargin).offset(10)
make.left.equalTo(iconImage.snp.right).offset(10)
make.centerY.equalToSuperview()
}

View File

@ -7,12 +7,15 @@
//
import UIKit
import FacebookCore
extension AppDelegate {
func setConfig() {
SRToast.config()
}
func sr_registThirdparty(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -16,7 +16,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
SRTool.appDelegate = self
SRNetworkReachableManager.manager.startMonitoring()
sr_registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
self.setConfig()
@ -24,6 +24,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
await SRAccountManager.manager.updateUserInfo()
}
return true
}

View File

@ -0,0 +1,60 @@
//
// SRLogin+FB.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import FacebookLogin
extension SRLogin {
func facebookLogin(presentingViewController: UIViewController?, completer: ((_ model: SRThirdModel?) -> Void)?) {
let loginManager = LoginManager()
loginManager.logOut()
loginManager.defaultAudience = .everyone
loginManager.logIn(permissions: ["public_profile", "email"], from: presentingViewController) { result, error in
guard error == nil, let result = result else {
completer?(nil)
return
}
if result.isCancelled {
completer?(nil)
return
}
let request = GraphRequest(graphPath: "me", parameters: ["fields" : "id,name,email,picture"], httpMethod: .get)
request.start { connection, result, error in
guard let result = result as? [String : Any] else {
completer?(nil)
return
}
var model = SRThirdModel()
model.platform = .faceBook
model.third_id = result["id"] as? String
model.email = result["email"] as? String
if let picture = result["picture"] as? [String : Any],
let data = picture["data"] as? [String : Any],
let url = data["url"] as? String
{
model.avator = url
}
if let name = result["name"] as? String {
model.family_name = name
} else {
model.family_name = result["first_name"] as? String
model.giving_name = result["last_name"] as? String
}
completer?(model)
}
}
}
}

View File

@ -0,0 +1,116 @@
//
// SRLogin+third.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import AuthenticationServices
extension SRLogin {
private struct AssociatedKeys {
static var appleLoginHandle: Int?
}
private var appleLoginHandle: ((_ model: SRThirdModel?) -> Void)? {
set {
objc_setAssociatedObject(self, &AssociatedKeys.appleLoginHandle, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &AssociatedKeys.appleLoginHandle) as? ((_ model: SRThirdModel?) -> Void)
}
}
func appleLogin(completer: ((_ model: SRThirdModel?) -> Void)?) {
self.appleLoginHandle = completer
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self
authorizationController.performRequests()
}
private func jwtDecode(jwtStr: String) -> [String: Any]? {
let segments = jwtStr.components(separatedBy: ".")
guard segments.count > 1 else { return nil }
var base64String = segments[1]
// Base64
let requiredLength = 4 * Int(ceil(Double(base64String.count) / 4.0))
let paddingLength = requiredLength - base64String.count
if paddingLength > 0 {
base64String += String(repeating: "=", count: paddingLength)
}
// URL
base64String = base64String.replacingOccurrences(of: "-", with: "+")
base64String = base64String.replacingOccurrences(of: "_", with: "/")
// Base64
guard let data = Data(base64Encoded: base64String),
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
let payload = jsonObject as? [String: Any] else {
return nil
}
return payload
}
}
//MARK: ASAuthorizationControllerDelegate
extension SRLogin: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
let identityToken = appleIDCredential.identityToken.flatMap { String(data: $0, encoding: .utf8) }
let identityTokenParams = self.jwtDecode(jwtStr: identityToken ?? "")
var model = SRThirdModel()
model.platform = .apple
model.third_id = userIdentifier
model.giving_name = fullName?.givenName
model.family_name = fullName?.familyName
model.avator = identityTokenParams?["picture"] as? String
model.email = identityTokenParams?["email"] as? String
debugLog(userIdentifier)
debugLog(fullName)
debugLog(email)
appleLoginHandle?(model)
appleLoginHandle = nil
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
appleLoginHandle?(nil)
appleLoginHandle = nil
}
}
//MARK: ASAuthorizationControllerPresentationContextProviding
extension SRLogin: ASAuthorizationControllerPresentationContextProviding {
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return SRTool.keyWindow!
}
}

View File

@ -0,0 +1,133 @@
//
// SRLogin.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import SmartCodable
class SRLogin: NSObject {
enum LoginType: String, SmartCaseDefaultable {
case apple = "Apple"
case faceBook = "Facebook"
case google = "Google"
case tiktok = "Tiktok"
}
static let manager = SRLogin()
private(set) var token = UserDefaults.sr_object(forKey: kSRAccountTokenDefaultsKey, as: SRTokenModel.self)
private(set) var userInfo = UserDefaults.sr_object(forKey: kSRUserInfoDefaultsKey, as: SRUserInfo.self)
var isLogin: Bool {
return !(userInfo?.is_tourist ?? true)
}
private func setToken(_ token: SRTokenModel?) {
self.token = token
UserDefaults.sr_setObject(token, forKey: kSRAccountTokenDefaultsKey)
}
private func setUserInfo(_ userInfo: SRUserInfo?) {
self.userInfo = userInfo
UserDefaults.sr_setObject(userInfo, forKey: kSRUserInfoDefaultsKey)
}
///
func thirdLogin(type: LoginType, presentingViewController: UIViewController?, completer: ((_ isFinish: Bool) -> Void)?) {
switch type {
case .apple:
appleLogin { [weak self] model in
self?.requestSignThirdLogin(thirdSignModel: model, completer: completer)
}
case .faceBook:
facebookLogin(presentingViewController: presentingViewController) { [weak self] model in
self?.requestSignThirdLogin(thirdSignModel: model, completer: completer)
}
default:
break
}
}
///
private func requestSignThirdLogin(thirdSignModel: SRThirdModel?, completer: ((_ isFinish: Bool) -> Void)?) {
guard let thirdSignModel = thirdSignModel else {
completer?(false)
return
}
Task {
await SRUserApi.requestLeave()
let tokenModel = await SRUserApi.requestSignThirdLogin(model: thirdSignModel)
guard let token = tokenModel else {
completer?(false)
return
}
self.setToken(token)
self.userInfo?.is_tourist = false
await self.requestUserInfo(completer: nil)
await SRUserApi.requestEnterApp()
await SRUserApi.requestStatOnLine()
completer?(true)
await MainActor.run {
NotificationCenter.default.post(name: SRLogin.userInfoUpdateNotification, object: nil)
NotificationCenter.default.post(name: SRLogin.loginStatusChangeNotification, object: nil)
}
}
}
func logout(completer: ((_ isFinish: Bool) -> Void)?) async {
await SRUserApi.requestLeave()
let tokenModel = await SRUserApi.requestLogout()
guard let token = tokenModel else {
completer?(false)
return
}
self.setToken(token)
self.userInfo?.is_tourist = true
await self.requestUserInfo(completer: nil)
await SRUserApi.requestEnterApp()
await SRUserApi.requestStatOnLine()
completer?(true)
await MainActor.run {
NotificationCenter.default.post(name: SRLogin.userInfoUpdateNotification, object: nil)
NotificationCenter.default.post(name: SRLogin.loginStatusChangeNotification, object: nil)
}
}
}
extension SRLogin {
func requestUserInfo(completer: (() -> Void)?) async {
let userInfo = await SRUserApi.requestUserInfo()
if let user = userInfo {
self.setUserInfo(user)
}
completer?()
}
func requestUserToken(completer: (() -> Void)?) async {
let tokenModel = await SRUserApi.requestregister()
if let token = tokenModel {
self.setToken(token)
}
completer?()
NotificationCenter.default.post(name: Self.userInfoUpdateNotification, object: nil)
}
}
extension SRLogin {
///
@objc static let userInfoUpdateNotification = NSNotification.Name(rawValue: "FALogin.userInfoUpdateNotification")
///
@objc static let loginStatusChangeNotification = NSNotification.Name(rawValue: "FALogin.loginStatusChangeNotification")
}

View File

@ -0,0 +1,24 @@
//
// SRThirdModel.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import SmartCodable
struct SRThirdModel: SmartCodable {
var third_id: String?
var email: String?
//
var family_name: String?
//
var giving_name: String?
var avator: String?
var platform: SRLogin.LoginType?
}

View File

@ -0,0 +1,37 @@
//
// SRTokenModel.swift
// SynthReel
//
// Created by CSGY on 2025/12/1.
// Copyright © 2025 SR. All rights reserved.
//
import UIKit
import SmartCodable
class SRTokenModel: NSObject,SmartCodable, NSSecureCoding {
var auto_login: Int?
var customer_id: String?
var token: String?
required override init() { }
static var supportsSecureCoding: Bool {
return true
}
func encode(with coder: NSCoder) {
coder.encode(token, forKey: "token")
coder.encode(customer_id, forKey: "customer_id")
coder.encode(auto_login, forKey: "auto_login")
}
required init?(coder: NSCoder) {
super.init()
token = coder.decodeObject(of: NSString.self, forKey: "token") as? String
customer_id = coder.decodeObject(of: NSString.self, forKey: "customer_id") as? String
auto_login = coder.decodeObject(of: NSNumber.self, forKey: "auto_login")?.intValue
}
}

View File

@ -8,6 +8,14 @@
import UIKit
#if DEBUG
func debugLog(_ msg: Any, file: String = #file, function: String = #function, line: Int = #line) {
print("\n\(Date(timeIntervalSinceNow: 8 * 60 * 60)) \(file.components(separatedBy: "/").last ?? "") \(function) \(line): \(msg)")
}
#else
func debugLog(_ msg: Any) { }
#endif
class SRTool {
static var appDelegate: AppDelegate?

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "apple_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "apple_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "fb_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "fb_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_login@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_login@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_logout@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_logout@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "topCoinPack@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "topCoinPack@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "unlockButtonBg@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "unlockButtonBg@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "claimAllHiglit@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "claimAllHiglit@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "claimAllNomarl@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "claimAllNomarl@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "FacebookBg@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "FacebookBg@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "adlock@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "adlock@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "appleBg@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "appleBg@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "lock@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "lock@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "loginBg@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "loginBg@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "userCoinCell@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "userCoinCell@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

View File

@ -2,8 +2,29 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIDesignRequiresCompatibility</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>synthreel</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>fb1765365954312054</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>1765365954312054</string>
<key>FacebookClientToken</key>
<string>7a0b78de0a5f0e04738e8596b1b50aaa</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
@ -21,5 +42,12 @@
</array>
</dict>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UIDesignRequiresCompatibility</key>
<true/>
</dict>
</plist>

View File

@ -34,6 +34,19 @@
"Keep the Drama Going" = "Keep the Drama Going";
"synthreel_feedback" = "FeedBack";
"synthreel_feedback_history" = "Feedback History";
"synthreel_login" = "login";
"synthreel_logout" = "logout";
"synthreel_feedback_detail" = "Feedback Details";
"synthreel_account_deletion" = "Account Deletion";
"Rewards" = "Rewards";
"Daily reward ready !" = "Daily reward ready !";
"Claim your rewards now" = "Claim your rewards now";
"My Refills" = "My Refills";
"synthreel_unlocking_coins_notice" = "Unlock";
"video_lock_tip_text" = "Pre.locked";
"Watch 2ads to unlock" = "Watch 2ads to unlock";
"synthreel_success" = "success";
"buy_fail_toast_01" = "Purchase failed, please try again later!";
"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";

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>