diff --git a/Podfile b/Podfile index 50e7ff7..6cf9cae 100644 --- a/Podfile +++ b/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' diff --git a/SynthReel.xcodeproj/project.pbxproj b/SynthReel.xcodeproj/project.pbxproj index 4b02797..3f8c6bd 100644 --- a/SynthReel.xcodeproj/project.pbxproj +++ b/SynthReel.xcodeproj/project.pbxproj @@ -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 = ""; }; 3754ACFD2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinsPackReceiveModel.swift; sourceTree = ""; }; 3754AD012EDA8AF7009EBCAD /* SRLoginController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRLoginController.swift; sourceTree = ""; }; + 3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRVideoLockView.swift; sourceTree = ""; }; + 3754AD1B2EDD77BA009EBCAD /* SRVideoUnlockResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRVideoUnlockResult.swift; sourceTree = ""; }; + 3754AD1D2EDD84DD009EBCAD /* SynthReel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SynthReel.entitlements; sourceTree = ""; }; + 3754AD302EDD939A009EBCAD /* SRUserLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserLoginView.swift; sourceTree = ""; }; + 3754AD322EDD96E0009EBCAD /* SRLoginButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRLoginButtonView.swift; sourceTree = ""; }; + 3754AD352EDD9AA7009EBCAD /* SRLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRLogin.swift; sourceTree = ""; }; + 3754AD372EDD9B5D009EBCAD /* SRTokenModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRTokenModel.swift; sourceTree = ""; }; + 3754AD392EDD9BB1009EBCAD /* SRLogin+apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRLogin+apple.swift"; sourceTree = ""; }; + 3754AD3B2EDD9C01009EBCAD /* SRThirdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRThirdModel.swift; sourceTree = ""; }; + 3754AD3D2EDD9C88009EBCAD /* SRLogin+FB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRLogin+FB.swift"; sourceTree = ""; }; + 3754AEF72EDE94CD009EBCAD /* SRUserRewardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUserRewardCell.swift; sourceTree = ""; }; 3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRShortHeaderView.swift; sourceTree = ""; }; 59DC746604B26E9FF802D317 /* Pods-SynthReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.debug.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.debug.xcconfig"; sourceTree = ""; }; AA88214030574193B51DE563 /* Pods-SynthReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.release.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.release.xcconfig"; sourceTree = ""; }; @@ -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 = ""; @@ -511,6 +549,7 @@ 03B1A94D2ECD604B006C353F /* SREpSelectorCell.swift */, 3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */, 3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */, + 3754AD192EDD745A009EBCAD /* SRVideoLockView.swift */, ); path = V; sourceTree = ""; @@ -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 = ""; @@ -825,6 +869,18 @@ path = VC; sourceTree = ""; }; + 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 = ""; + }; 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 */; diff --git a/SynthReel.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SynthReel.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4145a73..a5ab089 100644 --- a/SynthReel.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/SynthReel.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -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 diff --git a/SynthReel/Base/API/SRShortApi.swift b/SynthReel/Base/API/SRShortApi.swift index 1847058..b29df89 100644 --- a/SynthReel/Base/API/SRShortApi.swift +++ b/SynthReel/Base/API/SRShortApi.swift @@ -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) in + continuation.resume(returning: response.data) + } + } + } + + } diff --git a/SynthReel/Base/API/SRUserApi.swift b/SynthReel/Base/API/SRUserApi.swift index 40d6cc6..ff2daa6 100644 --- a/SynthReel/Base/API/SRUserApi.swift +++ b/SynthReel/Base/API/SRUserApi.swift @@ -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) 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) 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) 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) 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) 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) 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) 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) in + continuation.resume(returning: response.data) + } + } + } } diff --git a/SynthReel/Base/Networking/SRNetworkModel.swift b/SynthReel/Base/Networking/SRNetworkModel.swift index 755634d..953295a 100644 --- a/SynthReel/Base/Networking/SRNetworkModel.swift +++ b/SynthReel/Base/Networking/SRNetworkModel.swift @@ -30,7 +30,7 @@ extension SRNetwork { var data: T? var msg: String? - @SmartIgnored + @IgnoredKey var rawData: Any? var isSuccess: Bool { diff --git a/SynthReel/Base/View/SRPanModalContentView.swift b/SynthReel/Base/View/SRPanModalContentView.swift index 07604c3..cf5e474 100644 --- a/SynthReel/Base/View/SRPanModalContentView.swift +++ b/SynthReel/Base/View/SRPanModalContentView.swift @@ -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") } diff --git a/SynthReel/Class/Player/M/SRShortModel.swift b/SynthReel/Class/Player/M/SRShortModel.swift index 5960dae..868cdcd 100644 --- a/SynthReel/Class/Player/M/SRShortModel.swift +++ b/SynthReel/Class/Player/M/SRShortModel.swift @@ -32,7 +32,7 @@ class SRShortModel: NSObject, SmartCodable { var category_name :String? var category_id :String? - @SmartIgnored + @IgnoredKey var cellHeight: CGFloat = 0 diff --git a/SynthReel/Class/Player/M/SRVideoUnlockResult.swift b/SynthReel/Class/Player/M/SRVideoUnlockResult.swift new file mode 100644 index 0000000..a9850c3 --- /dev/null +++ b/SynthReel/Class/Player/M/SRVideoUnlockResult.swift @@ -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? +} diff --git a/SynthReel/Class/Player/V/SREpSelectorCell.swift b/SynthReel/Class/Player/V/SREpSelectorCell.swift index cfbec62..883acbe 100644 --- a/SynthReel/Class/Player/V/SREpSelectorCell.swift +++ b/SynthReel/Class/Player/V/SREpSelectorCell.swift @@ -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) + } + + } diff --git a/SynthReel/Class/Player/V/SREpSelectorView.swift b/SynthReel/Class/Player/V/SREpSelectorView.swift index 64aab68..5ca7123 100644 --- a/SynthReel/Class/Player/V/SREpSelectorView.swift +++ b/SynthReel/Class/Player/V/SREpSelectorView.swift @@ -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) diff --git a/SynthReel/Class/Player/V/SRShortDetailControlView.swift b/SynthReel/Class/Player/V/SRShortDetailControlView.swift index febdfb7..d2f0f9b 100644 --- a/SynthReel/Class/Player/V/SRShortDetailControlView.swift +++ b/SynthReel/Class/Player/V/SRShortDetailControlView.swift @@ -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() diff --git a/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift b/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift index 60e93f7..a50c9f5 100644 --- a/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift +++ b/SynthReel/Class/Player/V/SRShortDetailPlayerCell.swift @@ -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() + } + } + +} diff --git a/SynthReel/Class/Player/V/SRVideoLockView.swift b/SynthReel/Class/Player/V/SRVideoLockView.swift new file mode 100644 index 0000000..c90f6d2 --- /dev/null +++ b/SynthReel/Class/Player/V/SRVideoLockView.swift @@ -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) + } + } +} diff --git a/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift b/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift index 823bdb8..450a816 100644 --- a/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift +++ b/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift @@ -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 } diff --git a/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift b/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift index 76df98c..ec6a314 100644 --- a/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift +++ b/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift @@ -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 } diff --git a/SynthReel/Class/User/VC/SRHelpCenterController.swift b/SynthReel/Class/User/VC/SRHelpCenterController.swift index 104f783..54c7e6c 100644 --- a/SynthReel/Class/User/VC/SRHelpCenterController.swift +++ b/SynthReel/Class/User/VC/SRHelpCenterController.swift @@ -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. - } - */ } diff --git a/SynthReel/Class/User/VC/SRPrivacyController.swift b/SynthReel/Class/User/VC/SRPrivacyController.swift index 2bf5248..81e0ec5 100644 --- a/SynthReel/Class/User/VC/SRPrivacyController.swift +++ b/SynthReel/Class/User/VC/SRPrivacyController.swift @@ -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. - } - */ } diff --git a/SynthReel/Class/User/VC/SRRewardController.swift b/SynthReel/Class/User/VC/SRRewardController.swift index fab1993..83a3463 100644 --- a/SynthReel/Class/User/VC/SRRewardController.swift +++ b/SynthReel/Class/User/VC/SRRewardController.swift @@ -15,7 +15,4 @@ class SRRewardController: SRAppWebViewController { super.viewDidLoad() // Do any additional setup after loading the view. } - - - } diff --git a/SynthReel/Class/User/VC/SRUserViewController.swift b/SynthReel/Class/User/VC/SRUserViewController.swift index 119bdd2..5962a5b 100644 --- a/SynthReel/Class/User/VC/SRUserViewController.swift +++ b/SynthReel/Class/User/VC/SRUserViewController.swift @@ -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")), diff --git a/SynthReel/Class/User/model/SRUserSettingModel.swift b/SynthReel/Class/User/model/SRUserSettingModel.swift index 1f691ea..c002139 100644 --- a/SynthReel/Class/User/model/SRUserSettingModel.swift +++ b/SynthReel/Class/User/model/SRUserSettingModel.swift @@ -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 } diff --git a/SynthReel/Class/User/view/SRLoginButtonView.swift b/SynthReel/Class/User/view/SRLoginButtonView.swift new file mode 100644 index 0000000..9d762b9 --- /dev/null +++ b/SynthReel/Class/User/view/SRLoginButtonView.swift @@ -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) + } + } +} diff --git a/SynthReel/Class/User/view/SRUserLoginView.swift b/SynthReel/Class/User/view/SRUserLoginView.swift new file mode 100644 index 0000000..622a98b --- /dev/null +++ b/SynthReel/Class/User/view/SRUserLoginView.swift @@ -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) + } + } + } + + } +} diff --git a/SynthReel/Class/User/view/SRUserRewardCell.swift b/SynthReel/Class/User/view/SRUserRewardCell.swift new file mode 100644 index 0000000..57591cd --- /dev/null +++ b/SynthReel/Class/User/view/SRUserRewardCell.swift @@ -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 { + +} diff --git a/SynthReel/Class/User/view/SRUserSettingCell.swift b/SynthReel/Class/User/view/SRUserSettingCell.swift index cb8172f..29127a2 100644 --- a/SynthReel/Class/User/view/SRUserSettingCell.swift +++ b/SynthReel/Class/User/view/SRUserSettingCell.swift @@ -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() } diff --git a/SynthReel/Delegate/AppDelegate+Config.swift b/SynthReel/Delegate/AppDelegate+Config.swift index e85f72c..bbcace4 100644 --- a/SynthReel/Delegate/AppDelegate+Config.swift +++ b/SynthReel/Delegate/AppDelegate+Config.swift @@ -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) + } } diff --git a/SynthReel/Delegate/AppDelegate.swift b/SynthReel/Delegate/AppDelegate.swift index 17fcdfc..3f061ed 100644 --- a/SynthReel/Delegate/AppDelegate.swift +++ b/SynthReel/Delegate/AppDelegate.swift @@ -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 } diff --git a/SynthReel/Libs/SRLogin/SRLogin+FB.swift b/SynthReel/Libs/SRLogin/SRLogin+FB.swift new file mode 100644 index 0000000..82c0f61 --- /dev/null +++ b/SynthReel/Libs/SRLogin/SRLogin+FB.swift @@ -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) + } + + } + } + +} + diff --git a/SynthReel/Libs/SRLogin/SRLogin+apple.swift b/SynthReel/Libs/SRLogin/SRLogin+apple.swift new file mode 100644 index 0000000..ec3fcf7 --- /dev/null +++ b/SynthReel/Libs/SRLogin/SRLogin+apple.swift @@ -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! + } + +} + diff --git a/SynthReel/Libs/SRLogin/SRLogin.swift b/SynthReel/Libs/SRLogin/SRLogin.swift new file mode 100644 index 0000000..43bd9bb --- /dev/null +++ b/SynthReel/Libs/SRLogin/SRLogin.swift @@ -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") + +} diff --git a/SynthReel/Libs/SRLogin/SRThirdModel.swift b/SynthReel/Libs/SRLogin/SRThirdModel.swift new file mode 100644 index 0000000..731f5aa --- /dev/null +++ b/SynthReel/Libs/SRLogin/SRThirdModel.swift @@ -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? +} diff --git a/SynthReel/Libs/SRLogin/SRTokenModel.swift b/SynthReel/Libs/SRLogin/SRTokenModel.swift new file mode 100644 index 0000000..721fecf --- /dev/null +++ b/SynthReel/Libs/SRLogin/SRTokenModel.swift @@ -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 + } +} diff --git a/SynthReel/Libs/Tool/SRTool.swift b/SynthReel/Libs/Tool/SRTool.swift index fa663ba..1b36a0c 100644 --- a/SynthReel/Libs/Tool/SRTool.swift +++ b/SynthReel/Libs/Tool/SRTool.swift @@ -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? diff --git a/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/Contents.json new file mode 100644 index 0000000..12bcf04 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@2x.png b/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@2x.png new file mode 100644 index 0000000..2480333 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@3x.png b/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@3x.png new file mode 100644 index 0000000..24a5f62 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/apple_icon.imageset/apple_icon@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/Contents.json new file mode 100644 index 0000000..9c23f44 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@2x.png b/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@2x.png new file mode 100644 index 0000000..547954a Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@3x.png b/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@3x.png new file mode 100644 index 0000000..4ab53bc Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/fb_icon.imageset/fb_icon@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/Contents.json new file mode 100644 index 0000000..725c73f --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@2x.png b/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@2x.png new file mode 100644 index 0000000..5d62c34 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@3x.png b/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@3x.png new file mode 100644 index 0000000..4130ecb Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/icon_login.imageset/icon_login@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/Contents.json new file mode 100644 index 0000000..c918d58 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@2x.png b/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@2x.png new file mode 100644 index 0000000..baf563d Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@3x.png b/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@3x.png new file mode 100644 index 0000000..969055e Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/icon_logout.imageset/icon_logout@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/Contents.json new file mode 100644 index 0000000..0049803 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@2x.png b/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@2x.png new file mode 100644 index 0000000..243f723 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@3x.png b/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@3x.png new file mode 100644 index 0000000..9615efc Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/unlockButtonBg.imageset/unlockButtonBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/Contents.json new file mode 100644 index 0000000..f1f904b --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@2x.png new file mode 100644 index 0000000..daf6a13 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@3x.png new file mode 100644 index 0000000..fbed031 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/FacebookBg.imageset/FacebookBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/Contents.json new file mode 100644 index 0000000..c18b9c9 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@2x.png b/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@2x.png new file mode 100644 index 0000000..eb8e84b Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@3x.png b/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@3x.png new file mode 100644 index 0000000..9e19f4f Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/adlock.imageset/adlock@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/Contents.json new file mode 100644 index 0000000..8afe64e --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@2x.png new file mode 100644 index 0000000..775b695 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@3x.png new file mode 100644 index 0000000..b80cd17 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/appleBg.imageset/appleBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/Contents.json new file mode 100644 index 0000000..21769d5 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@2x.png b/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@2x.png new file mode 100644 index 0000000..8a96fc9 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@3x.png b/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@3x.png new file mode 100644 index 0000000..6ded6c0 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/lock.imageset/lock@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/Contents.json new file mode 100644 index 0000000..02c1833 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@2x.png new file mode 100644 index 0000000..7aadb7e Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@3x.png new file mode 100644 index 0000000..ee5c9ca Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/loginBg.imageset/loginBg@3x.png differ diff --git a/SynthReel/Source/Info.plist b/SynthReel/Source/Info.plist index e666e0f..bf59de1 100644 --- a/SynthReel/Source/Info.plist +++ b/SynthReel/Source/Info.plist @@ -2,8 +2,29 @@ - UIDesignRequiresCompatibility - + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + synthreel + + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + fb1765365954312054 + + + + FacebookAppID + 1765365954312054 + FacebookClientToken + 7a0b78de0a5f0e04738e8596b1b50aaa UIApplicationSceneManifest UIApplicationSupportsMultipleScenes @@ -21,5 +42,12 @@ + UIBackgroundModes + + fetch + remote-notification + + UIDesignRequiresCompatibility + diff --git a/SynthReel/Source/en.lproj/Localizable.strings b/SynthReel/Source/en.lproj/Localizable.strings index 363fa4a..5d0fb22 100644 --- a/SynthReel/Source/en.lproj/Localizable.strings +++ b/SynthReel/Source/en.lproj/Localizable.strings @@ -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"; diff --git a/SynthReel/SynthReel.entitlements b/SynthReel/SynthReel.entitlements new file mode 100644 index 0000000..80b5221 --- /dev/null +++ b/SynthReel/SynthReel.entitlements @@ -0,0 +1,12 @@ + + + + + aps-environment + development + com.apple.developer.applesignin + + Default + + +