登陆功能
2
Podfile
@ -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'
|
||||
|
||||
@ -146,6 +146,24 @@
|
||||
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 */
|
||||
@ -291,6 +309,17 @@
|
||||
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>"; };
|
||||
@ -302,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;
|
||||
};
|
||||
@ -477,6 +514,7 @@
|
||||
children = (
|
||||
03B1A8EE2EC72C78006C353F /* SRShortModel.swift */,
|
||||
03B1A9272ECC05B1006C353F /* SRShortDetailModel.swift */,
|
||||
3754AD1B2EDD77BA009EBCAD /* SRVideoUnlockResult.swift */,
|
||||
);
|
||||
path = M;
|
||||
sourceTree = "<group>";
|
||||
@ -511,6 +549,7 @@
|
||||
03B1A94D2ECD604B006C353F /* SREpSelectorCell.swift */,
|
||||
3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */,
|
||||
3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */,
|
||||
3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -536,6 +575,7 @@
|
||||
03E9A7C82EC47177000D1067 /* SynthReel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AD1D2EDD84DD009EBCAD /* SynthReel.entitlements */,
|
||||
03E9A7D02EC471D6000D1067 /* Delegate */,
|
||||
03E9A7D22EC47204000D1067 /* Base */,
|
||||
03E9A7D32EC4720F000D1067 /* Class */,
|
||||
@ -599,6 +639,7 @@
|
||||
03E9A7D42EC4764A000D1067 /* Libs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754AD342EDD9A8F009EBCAD /* SRLogin */,
|
||||
3754ACD82ED83724009EBCAD /* FSPagerView */,
|
||||
3754ACCF2ED81F2F009EBCAD /* Alert */,
|
||||
3754ACC22ED6ED92009EBCAD /* Empty */,
|
||||
@ -717,6 +758,9 @@
|
||||
370D2F242ED5807600571E77 /* SRAboutHeaderVIew.swift */,
|
||||
370D2F262ED581BB00571E77 /* SRAboutCell.swift */,
|
||||
3754ACF32ED98609009EBCAD /* SRCoinPackCell.swift */,
|
||||
3754AD302EDD939A009EBCAD /* SRUserLoginView.swift */,
|
||||
3754AD322EDD96E0009EBCAD /* SRLoginButtonView.swift */,
|
||||
3754AEF72EDE94CD009EBCAD /* SRUserRewardCell.swift */,
|
||||
);
|
||||
path = view;
|
||||
sourceTree = "<group>";
|
||||
@ -825,6 +869,18 @@
|
||||
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 = (
|
||||
@ -904,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 */;
|
||||
@ -1041,11 +1099,13 @@
|
||||
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 */,
|
||||
@ -1058,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 */,
|
||||
@ -1090,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 */,
|
||||
@ -1108,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 */,
|
||||
);
|
||||
@ -1141,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;
|
||||
@ -1160,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;
|
||||
@ -1184,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;
|
||||
@ -1201,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;
|
||||
@ -1380,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 */
|
||||
@ -1393,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 */;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ extension SRNetwork {
|
||||
var data: T?
|
||||
var msg: String?
|
||||
|
||||
@SmartIgnored
|
||||
@IgnoredKey
|
||||
var rawData: Any?
|
||||
|
||||
var isSuccess: Bool {
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ class SRShortModel: NSObject, SmartCodable {
|
||||
|
||||
var category_name :String?
|
||||
var category_id :String?
|
||||
@SmartIgnored
|
||||
@IgnoredKey
|
||||
var cellHeight: CGFloat = 0
|
||||
|
||||
|
||||
|
||||
25
SynthReel/Class/Player/M/SRVideoUnlockResult.swift
Normal 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?
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
120
SynthReel/Class/Player/V/SRVideoLockView.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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.
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@ -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.
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@ -15,7 +15,4 @@ class SRRewardController: SRAppWebViewController {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ class SRUserViewController: SRViewController {
|
||||
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 {
|
||||
@ -44,6 +45,8 @@ class SRUserViewController: SRViewController {
|
||||
setDataArr()
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -67,8 +70,12 @@ extension SRUserViewController: UICollectionViewDelegate, UICollectionViewDataSo
|
||||
} 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
|
||||
@ -102,6 +109,10 @@ extension SRUserViewController: UICollectionViewDelegate, UICollectionViewDataSo
|
||||
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)
|
||||
@ -157,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")),
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
66
SynthReel/Class/User/view/SRLoginButtonView.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
84
SynthReel/Class/User/view/SRUserLoginView.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
13
SynthReel/Class/User/view/SRUserRewardCell.swift
Normal 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 {
|
||||
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
60
SynthReel/Libs/SRLogin/SRLogin+FB.swift
Normal 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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
116
SynthReel/Libs/SRLogin/SRLogin+apple.swift
Normal 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!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
133
SynthReel/Libs/SRLogin/SRLogin.swift
Normal 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")
|
||||
|
||||
}
|
||||
24
SynthReel/Libs/SRLogin/SRThirdModel.swift
Normal 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?
|
||||
}
|
||||
37
SynthReel/Libs/SRLogin/SRTokenModel.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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?
|
||||
|
||||
22
SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
22
SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
22
SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 750 B |
BIN
SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1004 B |
22
SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 921 B |
BIN
SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
22
SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 29 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 28 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 648 B |
BIN
SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 880 B |
22
SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/lock.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 146 KiB |
@ -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>
|
||||
|
||||
@ -34,9 +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";
|
||||
|
||||
12
SynthReel/SynthReel.entitlements
Normal 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>
|
||||