From 67eeef0447a8de256ac83ad0bb7920147abd3af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BE=9C=E5=A3=B0=E4=B8=96=E7=BA=AA?= <> Date: Thu, 11 Dec 2025 11:17:46 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=BC=80=E5=B1=8F=E5=B9=BF=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Podfile | 4 +- SynthReel.xcodeproj/project.pbxproj | 178 ++++++++++- SynthReel/Base/API/SRUserApi.swift | 13 + .../AppOpen/VPAppOpenAdManager.swift | 225 ++++++++++++++ .../AppOpen/VPApplovinAppOpenAd.swift | 84 +++++ .../AdManager/Banner/VPApplovinBannerAd.swift | 88 ++++++ .../AdManager/Banner/VPBannerAdManager.swift | 131 ++++++++ .../Rewarded/VPApplovinRewardedAd.swift | 91 ++++++ .../Rewarded/VPGoogleRewardedAd.swift | 101 ++++++ .../Rewarded/VPRewardedAdManager.swift | 292 ++++++++++++++++++ SynthReel/Base/AdManager/VPAdInfo.swift | 40 +++ SynthReel/Base/AdManager/VPAdManager.swift | 100 ++++++ SynthReel/Base/AdManager/VPStatAdModel.swift | 33 ++ .../Admanger/BannerAd/SRAdmobOpenAd.swift | 137 ++++++++ .../Admanger/OpenAd/SROpenAdManager.swift | 227 ++++++++++++++ SynthReel/Base/Admanger/SRAdManger.swift | 101 ++++++ .../Base/Model/SRVersionUpdateModel.swift | 39 +++ SynthReel/Base/Networking/SRNetwork.swift | 8 +- .../Base/View/SRNavgationTitleView.swift | 2 +- .../SRAppOpenAdViewController.swift | 53 ++++ .../ViewController/SRTabBarController.swift | 3 + .../Class/MyShort/V/SRFavoritesCell.swift | 30 +- .../Player/V/SRShortDetailControlView.swift | 25 +- .../Class/Player/V/SRVideoLockView.swift | 11 +- .../Class/User/VC/SRAboutUsController.swift | 8 +- .../User/VC/SRUserListViewController.swift | 13 +- .../Class/User/model/SRUserSettingModel.swift | 1 + .../wallet/VC/SRWalletViewController.swift | 29 ++ SynthReel/Delegate/AppDelegate+SRAPNS.swift | 1 - SynthReel/Libs/Alert/SRApnsAlert.swift | 39 ++- SynthReel/Libs/Alert/SRBaseAlert.swift | 2 - SynthReel/Libs/Alert/SRLogoutAlert.swift | 117 +++++++ .../Libs/Alert/SRRemoveCollectAlert.swift | 117 +++++++ SynthReel/Libs/Alert/SRUpdatesAlert.swift | 107 +++++++ SynthReel/Libs/Tool/SRTool.swift | 53 ++++ .../recordBottomBg.imageset/Contents.json | 22 ++ .../myShort/icon_order.imageset/Contents.json | 22 ++ .../icon_order.imageset/icon_order@2x.png | Bin 0 -> 691 bytes .../icon_order.imageset/icon_order@3x.png | Bin 0 -> 852 bytes .../suerButtonBg.imageset/Contents.json | 22 ++ .../normal/laterbg.imageset/Contents.json | 22 ++ .../normal/laterbg.imageset/laterbg@2x.png | Bin 0 -> 1732 bytes .../normal/laterbg.imageset/laterbg@3x.png | Bin 0 -> 2699 bytes .../normal/删除.imageset/Contents.json | 22 ++ .../normal/删除.imageset/删除@2x.png | Bin 0 -> 980 bytes .../normal/删除.imageset/删除@3x.png | Bin 0 -> 1580 bytes .../弹窗按钮背景.imageset/Contents.json | 22 ++ .../normal/收藏.imageset/Contents.json | 22 ++ .../normal/收藏.imageset/收藏@2x.png | Bin 0 -> 19801 bytes .../normal/收藏.imageset/收藏@3x.png | Bin 0 -> 38846 bytes SynthReel/Source/Info.plist | 2 + SynthReel/Source/en.lproj/Localizable.strings | 13 + SynthReel/SynthReel.entitlements | 4 + .../build-request.json | 27 ++ .../description.msgpack | Bin 0 -> 253 bytes .../manifest.json | 1 + .../target-graph.txt | 1 + .../task-store.msgpack | Bin 0 -> 79 bytes 58 files changed, 2653 insertions(+), 52 deletions(-) create mode 100644 SynthReel/Base/AdManager/AppOpen/VPAppOpenAdManager.swift create mode 100644 SynthReel/Base/AdManager/AppOpen/VPApplovinAppOpenAd.swift create mode 100644 SynthReel/Base/AdManager/Banner/VPApplovinBannerAd.swift create mode 100644 SynthReel/Base/AdManager/Banner/VPBannerAdManager.swift create mode 100644 SynthReel/Base/AdManager/Rewarded/VPApplovinRewardedAd.swift create mode 100644 SynthReel/Base/AdManager/Rewarded/VPGoogleRewardedAd.swift create mode 100644 SynthReel/Base/AdManager/Rewarded/VPRewardedAdManager.swift create mode 100644 SynthReel/Base/AdManager/VPAdInfo.swift create mode 100644 SynthReel/Base/AdManager/VPAdManager.swift create mode 100644 SynthReel/Base/AdManager/VPStatAdModel.swift create mode 100644 SynthReel/Base/Admanger/BannerAd/SRAdmobOpenAd.swift create mode 100644 SynthReel/Base/Admanger/OpenAd/SROpenAdManager.swift create mode 100644 SynthReel/Base/Admanger/SRAdManger.swift create mode 100644 SynthReel/Base/Model/SRVersionUpdateModel.swift create mode 100644 SynthReel/Base/ViewController/SRAppOpenAdViewController.swift create mode 100644 SynthReel/Class/wallet/VC/SRWalletViewController.swift create mode 100644 SynthReel/Libs/Alert/SRLogoutAlert.swift create mode 100644 SynthReel/Libs/Alert/SRRemoveCollectAlert.swift create mode 100644 SynthReel/Libs/Alert/SRUpdatesAlert.swift create mode 100644 SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/Contents.json create mode 100644 SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/icon_order@2x.png create mode 100644 SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/icon_order@3x.png create mode 100644 SynthReel/Source/Assets.xcassets/normal/laterbg.imageset/Contents.json create mode 100644 SynthReel/Source/Assets.xcassets/normal/laterbg.imageset/laterbg@2x.png create mode 100644 SynthReel/Source/Assets.xcassets/normal/laterbg.imageset/laterbg@3x.png create mode 100644 SynthReel/Source/Assets.xcassets/normal/删除.imageset/Contents.json create mode 100644 SynthReel/Source/Assets.xcassets/normal/删除.imageset/删除@2x.png create mode 100644 SynthReel/Source/Assets.xcassets/normal/删除.imageset/删除@3x.png create mode 100644 SynthReel/Source/Assets.xcassets/normal/收藏.imageset/Contents.json create mode 100644 SynthReel/Source/Assets.xcassets/normal/收藏.imageset/收藏@2x.png create mode 100644 SynthReel/Source/Assets.xcassets/normal/收藏.imageset/收藏@3x.png create mode 100644 build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/build-request.json create mode 100644 build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/description.msgpack create mode 100644 build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/manifest.json create mode 100644 build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/target-graph.txt create mode 100644 build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/task-store.msgpack diff --git a/Podfile b/Podfile index 85d58a7..7555a03 100644 --- a/Podfile +++ b/Podfile @@ -36,8 +36,8 @@ target 'SynthReel' do pod 'Adjust' # # AdMob SDK -# pod 'Google-Mobile-Ads-SDK' + pod 'Google-Mobile-Ads-SDK' # # # AppLovin SDK -# pod 'AppLovinSDK' + pod 'AppLovinSDK' end diff --git a/SynthReel.xcodeproj/project.pbxproj b/SynthReel.xcodeproj/project.pbxproj index c02d323..9976690 100644 --- a/SynthReel.xcodeproj/project.pbxproj +++ b/SynthReel.xcodeproj/project.pbxproj @@ -205,6 +205,25 @@ 85AE54782EE8106F0058FEA3 /* SRApnsAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AE54772EE8106F0058FEA3 /* SRApnsAlert.swift */; }; 85AE547A2EE8154A0058FEA3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 85AE54792EE8154A0058FEA3 /* GoogleService-Info.plist */; }; 85AE549C2EE81E730058FEA3 /* SRAppStartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AE549B2EE81E730058FEA3 /* SRAppStartViewController.swift */; }; + 85DFB3B12EE957A800CBD0FC /* SRUpdatesAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3B02EE957A800CBD0FC /* SRUpdatesAlert.swift */; }; + 85DFB3B32EE95EFB00CBD0FC /* SRVersionUpdateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3B22EE95EFB00CBD0FC /* SRVersionUpdateModel.swift */; }; + 85DFB3B52EE96B8600CBD0FC /* SRLogoutAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3B42EE96B8600CBD0FC /* SRLogoutAlert.swift */; }; + 85DFB3B72EE9766000CBD0FC /* SRRemoveCollectAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3B62EE9766000CBD0FC /* SRRemoveCollectAlert.swift */; }; + 85DFB3BB2EE97A1E00CBD0FC /* SRWalletViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3BA2EE97A1E00CBD0FC /* SRWalletViewController.swift */; }; + 85DFB3BF2EE991D400CBD0FC /* SROpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3BE2EE991D400CBD0FC /* SROpenAdManager.swift */; }; + 85DFB3CE2EEA51A900CBD0FC /* VPBannerAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3C42EEA51A900CBD0FC /* VPBannerAdManager.swift */; }; + 85DFB3CF2EEA51A900CBD0FC /* VPAdInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3CA2EEA51A900CBD0FC /* VPAdInfo.swift */; }; + 85DFB3D02EEA51A900CBD0FC /* VPAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3CB2EEA51A900CBD0FC /* VPAdManager.swift */; }; + 85DFB3D12EEA51A900CBD0FC /* VPGoogleRewardedAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3C72EEA51A900CBD0FC /* VPGoogleRewardedAd.swift */; }; + 85DFB3D22EEA51A900CBD0FC /* VPApplovinRewardedAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3C62EEA51A900CBD0FC /* VPApplovinRewardedAd.swift */; }; + 85DFB3D32EEA51A900CBD0FC /* VPApplovinBannerAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3C32EEA51A900CBD0FC /* VPApplovinBannerAd.swift */; }; + 85DFB3D42EEA51A900CBD0FC /* VPStatAdModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3CC2EEA51A900CBD0FC /* VPStatAdModel.swift */; }; + 85DFB3D52EEA51A900CBD0FC /* VPAppOpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3C12EEA51A900CBD0FC /* VPAppOpenAdManager.swift */; }; + 85DFB3D62EEA51A900CBD0FC /* VPRewardedAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3C82EEA51A900CBD0FC /* VPRewardedAdManager.swift */; }; + 85DFB3D72EEA51A900CBD0FC /* VPApplovinAppOpenAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3C02EEA51A900CBD0FC /* VPApplovinAppOpenAd.swift */; }; + 85DFB3D92EEA523B00CBD0FC /* SRAdManger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3D82EEA523B00CBD0FC /* SRAdManger.swift */; }; + 85DFB3DD2EEA5D5A00CBD0FC /* SRAdmobOpenAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3DC2EEA5D5A00CBD0FC /* SRAdmobOpenAd.swift */; }; + 85DFB3DF2EEA671C00CBD0FC /* SRAppOpenAdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DFB3DE2EEA671C00CBD0FC /* SRAppOpenAdViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -534,6 +553,25 @@ 85AE54822EE818180058FEA3 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 85AE549A2EE8183A0058FEA3 /* SynthReel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SynthReel.entitlements; sourceTree = ""; }; 85AE549B2EE81E730058FEA3 /* SRAppStartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRAppStartViewController.swift; sourceTree = ""; }; + 85DFB3B02EE957A800CBD0FC /* SRUpdatesAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRUpdatesAlert.swift; sourceTree = ""; }; + 85DFB3B22EE95EFB00CBD0FC /* SRVersionUpdateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRVersionUpdateModel.swift; sourceTree = ""; }; + 85DFB3B42EE96B8600CBD0FC /* SRLogoutAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRLogoutAlert.swift; sourceTree = ""; }; + 85DFB3B62EE9766000CBD0FC /* SRRemoveCollectAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRRemoveCollectAlert.swift; sourceTree = ""; }; + 85DFB3BA2EE97A1E00CBD0FC /* SRWalletViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRWalletViewController.swift; sourceTree = ""; }; + 85DFB3BE2EE991D400CBD0FC /* SROpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SROpenAdManager.swift; sourceTree = ""; }; + 85DFB3C02EEA51A900CBD0FC /* VPApplovinAppOpenAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPApplovinAppOpenAd.swift; sourceTree = ""; }; + 85DFB3C12EEA51A900CBD0FC /* VPAppOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAppOpenAdManager.swift; sourceTree = ""; }; + 85DFB3C32EEA51A900CBD0FC /* VPApplovinBannerAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPApplovinBannerAd.swift; sourceTree = ""; }; + 85DFB3C42EEA51A900CBD0FC /* VPBannerAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPBannerAdManager.swift; sourceTree = ""; }; + 85DFB3C62EEA51A900CBD0FC /* VPApplovinRewardedAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPApplovinRewardedAd.swift; sourceTree = ""; }; + 85DFB3C72EEA51A900CBD0FC /* VPGoogleRewardedAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPGoogleRewardedAd.swift; sourceTree = ""; }; + 85DFB3C82EEA51A900CBD0FC /* VPRewardedAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPRewardedAdManager.swift; sourceTree = ""; }; + 85DFB3CA2EEA51A900CBD0FC /* VPAdInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAdInfo.swift; sourceTree = ""; }; + 85DFB3CB2EEA51A900CBD0FC /* VPAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAdManager.swift; sourceTree = ""; }; + 85DFB3CC2EEA51A900CBD0FC /* VPStatAdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPStatAdModel.swift; sourceTree = ""; }; + 85DFB3D82EEA523B00CBD0FC /* SRAdManger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRAdManger.swift; sourceTree = ""; }; + 85DFB3DC2EEA5D5A00CBD0FC /* SRAdmobOpenAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRAdmobOpenAd.swift; sourceTree = ""; }; + 85DFB3DE2EEA671C00CBD0FC /* SRAppOpenAdViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRAppOpenAdViewController.swift; 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 = ""; }; F9255BF4D4B1CFDDB5CFFB43 /* Pods_SynthReel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SynthReel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -604,6 +642,7 @@ 03B1A8442EC5CBBB006C353F /* SRNavigationController.swift */, 03B1A8462EC5CBCF006C353F /* SRViewController.swift */, 85AE549B2EE81E730058FEA3 /* SRAppStartViewController.swift */, + 85DFB3DE2EEA671C00CBD0FC /* SRAppOpenAdViewController.swift */, ); path = ViewController; sourceTree = ""; @@ -835,6 +874,8 @@ 03E9A7D22EC47204000D1067 /* Base */ = { isa = PBXGroup; children = ( + 85DFB3CD2EEA51A900CBD0FC /* AdManager */, + 85DFB3BC2EE9919000CBD0FC /* Admanger */, 85AE54742EE80D7A0058FEA3 /* Model */, 3754ACE22ED93E04009EBCAD /* webview */, 03B1A8412EC5CB4F006C353F /* ViewController */, @@ -850,6 +891,7 @@ 03E9A7D32EC4720F000D1067 /* Class */ = { isa = PBXGroup; children = ( + 85DFB3B82EE979FE00CBD0FC /* wallet */, 3754ACFF2EDA8A43009EBCAD /* Login */, 3754ACF92ED9A34E009EBCAD /* Store */, 3754ACDD2ED93C14009EBCAD /* Coinpack */, @@ -1020,6 +1062,9 @@ children = ( 3754ACD02ED81F55009EBCAD /* SRBaseAlert.swift */, 85AE54772EE8106F0058FEA3 /* SRApnsAlert.swift */, + 85DFB3B02EE957A800CBD0FC /* SRUpdatesAlert.swift */, + 85DFB3B42EE96B8600CBD0FC /* SRLogoutAlert.swift */, + 85DFB3B62EE9766000CBD0FC /* SRRemoveCollectAlert.swift */, ); path = Alert; sourceTree = ""; @@ -1586,10 +1631,102 @@ isa = PBXGroup; children = ( 85AE54752EE80D900058FEA3 /* SROpenAppModel.swift */, + 85DFB3B22EE95EFB00CBD0FC /* SRVersionUpdateModel.swift */, ); path = Model; sourceTree = ""; }; + 85DFB3B82EE979FE00CBD0FC /* wallet */ = { + isa = PBXGroup; + children = ( + 85DFB3B92EE97A0700CBD0FC /* VC */, + ); + path = wallet; + sourceTree = ""; + }; + 85DFB3B92EE97A0700CBD0FC /* VC */ = { + isa = PBXGroup; + children = ( + 85DFB3BA2EE97A1E00CBD0FC /* SRWalletViewController.swift */, + ); + path = VC; + sourceTree = ""; + }; + 85DFB3BC2EE9919000CBD0FC /* Admanger */ = { + isa = PBXGroup; + children = ( + 85DFB3DB2EEA563700CBD0FC /* RewardAd */, + 85DFB3DA2EEA562700CBD0FC /* BannerAd */, + 85DFB3BD2EE991B400CBD0FC /* OpenAd */, + 85DFB3D82EEA523B00CBD0FC /* SRAdManger.swift */, + ); + path = Admanger; + sourceTree = ""; + }; + 85DFB3BD2EE991B400CBD0FC /* OpenAd */ = { + isa = PBXGroup; + children = ( + 85DFB3BE2EE991D400CBD0FC /* SROpenAdManager.swift */, + ); + path = OpenAd; + sourceTree = ""; + }; + 85DFB3C22EEA51A900CBD0FC /* AppOpen */ = { + isa = PBXGroup; + children = ( + 85DFB3C02EEA51A900CBD0FC /* VPApplovinAppOpenAd.swift */, + 85DFB3C12EEA51A900CBD0FC /* VPAppOpenAdManager.swift */, + ); + path = AppOpen; + sourceTree = ""; + }; + 85DFB3C52EEA51A900CBD0FC /* Banner */ = { + isa = PBXGroup; + children = ( + 85DFB3C32EEA51A900CBD0FC /* VPApplovinBannerAd.swift */, + 85DFB3C42EEA51A900CBD0FC /* VPBannerAdManager.swift */, + ); + path = Banner; + sourceTree = ""; + }; + 85DFB3C92EEA51A900CBD0FC /* Rewarded */ = { + isa = PBXGroup; + children = ( + 85DFB3C62EEA51A900CBD0FC /* VPApplovinRewardedAd.swift */, + 85DFB3C72EEA51A900CBD0FC /* VPGoogleRewardedAd.swift */, + 85DFB3C82EEA51A900CBD0FC /* VPRewardedAdManager.swift */, + ); + path = Rewarded; + sourceTree = ""; + }; + 85DFB3CD2EEA51A900CBD0FC /* AdManager */ = { + isa = PBXGroup; + children = ( + 85DFB3C22EEA51A900CBD0FC /* AppOpen */, + 85DFB3C52EEA51A900CBD0FC /* Banner */, + 85DFB3C92EEA51A900CBD0FC /* Rewarded */, + 85DFB3CA2EEA51A900CBD0FC /* VPAdInfo.swift */, + 85DFB3CB2EEA51A900CBD0FC /* VPAdManager.swift */, + 85DFB3CC2EEA51A900CBD0FC /* VPStatAdModel.swift */, + ); + path = AdManager; + sourceTree = ""; + }; + 85DFB3DA2EEA562700CBD0FC /* BannerAd */ = { + isa = PBXGroup; + children = ( + 85DFB3DC2EEA5D5A00CBD0FC /* SRAdmobOpenAd.swift */, + ); + path = BannerAd; + sourceTree = ""; + }; + 85DFB3DB2EEA563700CBD0FC /* RewardAd */ = { + isa = PBXGroup; + children = ( + ); + path = RewardAd; + sourceTree = ""; + }; 8CAFCEC2C631CAE75726D90C /* Pods */ = { isa = PBXGroup; children = ( @@ -1622,6 +1759,7 @@ 03E9A7A52EC4716A000D1067 /* Resources */, 92A47CFFAED31670C9452A17 /* [CP] Embed Pods Frameworks */, 85AE54992EE818190058FEA3 /* Embed Foundation Extensions */, + E78E68FAEB858A89EA05FB90 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -1729,6 +1867,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + E78E68FAEB858A89EA05FB90 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SynthReel/Pods-SynthReel-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SynthReel/Pods-SynthReel-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SynthReel/Pods-SynthReel-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1740,6 +1895,7 @@ 85AE54682EE7F7940058FEA3 /* SRCoinPackCanReceiveModel.swift in Sources */, 03E9A7EA2EC4995D000D1067 /* SRKeychain.swift in Sources */, 03E9A7D92EC47B90000D1067 /* SRNetworkReachableManager.swift in Sources */, + 85DFB3B32EE95EFB00CBD0FC /* SRVersionUpdateModel.swift in Sources */, 3754ACF82ED9A32C009EBCAD /* SRCoinPackHeaderView.swift in Sources */, 3754ACD72ED82774009EBCAD /* SRDetailRecommendCell.swift in Sources */, 370D2F2D2ED5AA9700571E77 /* SRViralHitCell.swift in Sources */, @@ -1750,6 +1906,7 @@ 03B1A8E12EC6D6D3006C353F /* SRHomeMenuDataSource.swift in Sources */, 03E9A7F82EC4AA54000D1067 /* SRUserDefaultsKey.swift in Sources */, 3754B0312EE2C9D4009EBCAD /* SRVideoRechargeView.swift in Sources */, + 85DFB3BB2EE97A1E00CBD0FC /* SRWalletViewController.swift in Sources */, 3754AF1C2EDEF112009EBCAD /* SRStoreCoinsView.swift in Sources */, 03B1A8452EC5CBBB006C353F /* SRNavigationController.swift in Sources */, 85AE54712EE80AFE0058FEA3 /* adjustManger.swift in Sources */, @@ -1760,6 +1917,17 @@ 3754B0112EE1248D009EBCAD /* SRCoinsPackBuyView.swift in Sources */, 03B1A9462ECC5679006C353F /* SRSearchResultCell.swift in Sources */, 03B1A9502ECEB4E6006C353F /* SRRecommendPlayerViewController.swift in Sources */, + 85DFB3CE2EEA51A900CBD0FC /* VPBannerAdManager.swift in Sources */, + 85DFB3CF2EEA51A900CBD0FC /* VPAdInfo.swift in Sources */, + 85DFB3D02EEA51A900CBD0FC /* VPAdManager.swift in Sources */, + 85DFB3DD2EEA5D5A00CBD0FC /* SRAdmobOpenAd.swift in Sources */, + 85DFB3D12EEA51A900CBD0FC /* VPGoogleRewardedAd.swift in Sources */, + 85DFB3D22EEA51A900CBD0FC /* VPApplovinRewardedAd.swift in Sources */, + 85DFB3D32EEA51A900CBD0FC /* VPApplovinBannerAd.swift in Sources */, + 85DFB3D42EEA51A900CBD0FC /* VPStatAdModel.swift in Sources */, + 85DFB3D52EEA51A900CBD0FC /* VPAppOpenAdManager.swift in Sources */, + 85DFB3D62EEA51A900CBD0FC /* VPRewardedAdManager.swift in Sources */, + 85DFB3D72EEA51A900CBD0FC /* VPApplovinAppOpenAd.swift in Sources */, 03B1A83E2EC5C91E006C353F /* SRTool.swift in Sources */, 03B1A9172ECAF14F006C353F /* SRHomeHotView.swift in Sources */, 03B1A8FD2EC81C62006C353F /* SRHomeBannerCell.swift in Sources */, @@ -1781,6 +1949,7 @@ 3754B0152EE12521009EBCAD /* SRCoinPackConfirmView.swift in Sources */, 370D2F2F2ED5AB2500571E77 /* SRViralHitController.swift in Sources */, 3754ACDA2ED8374D009EBCAD /* SRPagerViewTransformer.swift in Sources */, + 85DFB3BF2EE991D400CBD0FC /* SROpenAdManager.swift in Sources */, 3754AF282EDEF3CC009EBCAD /* SRPackCoinViewCell.swift in Sources */, 3754ACFE2ED9A3A0009EBCAD /* SRCoinsPackReceiveModel.swift in Sources */, 3754ACF22ED975B9009EBCAD /* SRRewardController.swift in Sources */, @@ -1793,7 +1962,9 @@ 03B1A8F32EC809C5006C353F /* SRHomeHeaderView.swift in Sources */, 03B1A9482ECC6669006C353F /* SRProgressView.swift in Sources */, 370D2F1A2ED45CCA00571E77 /* SRUserSettingCell.swift in Sources */, + 85DFB3B72EE9766000CBD0FC /* SRRemoveCollectAlert.swift in Sources */, 03B1A91D2ECB2424006C353F /* UIScrollView+SRAdd.swift in Sources */, + 85DFB3D92EEA523B00CBD0FC /* SRAdManger.swift in Sources */, 3754ACE62ED93E7C009EBCAD /* SRWebView.swift in Sources */, 3754ACEE2ED945A1009EBCAD /* Dictionary+SRAdd.swift in Sources */, 03E9A7C92EC47177000D1067 /* AppDelegate.swift in Sources */, @@ -1822,6 +1993,7 @@ 03B1A9152ECAEE63006C353F /* SRHomeViralHitsCell.swift in Sources */, 85AE546E2EE809850058FEA3 /* AppDelegate+SRAPNS.swift in Sources */, 03B1A8472EC5CBCF006C353F /* SRViewController.swift in Sources */, + 85DFB3B52EE96B8600CBD0FC /* SRLogoutAlert.swift in Sources */, 3754AF192EDEF0AF009EBCAD /* SRStoreController.swift in Sources */, 370D2F052ED3FEE700571E77 /* SRHistoryCell.swift in Sources */, 3754AF202EDEF133009EBCAD /* SRStoreVipView.swift in Sources */, @@ -1838,6 +2010,7 @@ 3754ACEC2ED943AB009EBCAD /* SRAppWebViewController.swift in Sources */, 03B1A9442ECC4ED9006C353F /* SRSearchResultView.swift in Sources */, 3754ACBF2ED5B839009EBCAD /* SRNavgationTitleView.swift in Sources */, + 85DFB3B12EE957A800CBD0FC /* SRUpdatesAlert.swift in Sources */, 3754B00B2EE12040009EBCAD /* SRCoinsPackClaimListView.swift in Sources */, 03B1A8FF2EC81C92006C353F /* SRImageView.swift in Sources */, 3754B00F2EE120C5009EBCAD /* SRCoinsPackClaimListCell.swift in Sources */, @@ -1874,6 +2047,7 @@ 3754AF042EDED773009EBCAD /* SRIapManager.swift in Sources */, 03B1A92E2ECC0D7E006C353F /* SRShortDetailControlView.swift in Sources */, 03B1A9382ECC210D006C353F /* SRSearchRecordCell.swift in Sources */, + 85DFB3DF2EEA671C00CBD0FC /* SRAppOpenAdViewController.swift in Sources */, 03E9A7D72EC47A23000D1067 /* SRResponseCryptor.swift in Sources */, 03B1A8502EC5DB2E006C353F /* SRHomeViewController.swift in Sources */, 03B1A8E52EC715E1006C353F /* SRHomeApi.swift in Sources */, @@ -1968,7 +2142,7 @@ CODE_SIGN_ENTITLEMENTS = SynthReel/SynthReel.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1.1; + CURRENT_PROJECT_VERSION = 1.2; DEVELOPMENT_TEAM = 9JR2Y32ZU3; EXCLUDED_ARCHS = ""; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; @@ -2012,7 +2186,7 @@ CODE_SIGN_ENTITLEMENTS = SynthReel/SynthReel.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1.1; + CURRENT_PROJECT_VERSION = 1.2; DEVELOPMENT_TEAM = 9JR2Y32ZU3; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SynthReel/Source/Info.plist; diff --git a/SynthReel/Base/API/SRUserApi.swift b/SynthReel/Base/API/SRUserApi.swift index f6d36bb..dedc235 100644 --- a/SynthReel/Base/API/SRUserApi.swift +++ b/SynthReel/Base/API/SRUserApi.swift @@ -124,4 +124,17 @@ struct SRUserApi { } } } + + static func requestVersionUpdateData() async -> SRVersionUpdateModel?{ + await withCheckedContinuation { continuation in + var param = SRNetwork.Parameters(path: "/customer/versionControl") + param.method = .get + SRNetwork.request(parameters: param) { (response: SRNetwork.Response) in + continuation.resume(returning: response.data) + } + } + } + + + } diff --git a/SynthReel/Base/AdManager/AppOpen/VPAppOpenAdManager.swift b/SynthReel/Base/AdManager/AppOpen/VPAppOpenAdManager.swift new file mode 100644 index 0000000..e763c36 --- /dev/null +++ b/SynthReel/Base/AdManager/AppOpen/VPAppOpenAdManager.swift @@ -0,0 +1,225 @@ +//// +//// VPAppOpenAdManager.swift +//// Veloria +//// +//// Created by 湖南秦九 on 2025/7/15. +//// +// +//import UIKit +// +// +//@objc protocol VPAppOpenAdManagerDelegate: NSObjectProtocol { +// +// ///广告加载成功 +// @objc optional func appOpenAdManagerDidLoadFinish(adManager: VPAppOpenAdManager) +// ///广告加载失败 +// @objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didLoadFail error: Error) +// ///广告展示失败 +// @objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didDisplayFail error: Error) +// ///广告被展示 +// @objc optional func appOpenAdManagerDidShow(adManager: VPAppOpenAdManager) +// ///广告被关闭 +// @objc optional func appOpenAdManagerDidDismiss(adManager: VPAppOpenAdManager) +// ///广告被点击 +// @objc optional func appOpenAdManagerDidClick(adManager: VPAppOpenAdManager) +// ///其它错误 +// @objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didOtherFail error: Error) +// +//} +// +// +//@objc protocol VPAppOpenAdDelegate: NSObjectProtocol { +// +// ///广告加载失败 +// @objc optional func appOpenAd(ad: VPAppOpenAd, didLoadFail error: Error) +// ///广告加载成功 +// @objc optional func appOpenAdDidLoadFinish(ad: VPAppOpenAd) +// ///广告展示失败 +// @objc optional func appOpenAd(ad: VPAppOpenAd, didDisplayFail error: Error) +// ///广告被展示 +// @objc optional func appOpenAdDidShow(ad: VPAppOpenAd) +// ///广告被关闭 +// @objc optional func appOpenAdDidDismiss(ad: VPAppOpenAd) +// ///广告被点击 +// @objc optional func appOpenAdDidClick(ad: VPAppOpenAd) +//} +// +//@objc protocol VPAppOpenAd: NSObjectProtocol { +// +// weak var delegate: VPAppOpenAdDelegate? { get set } +// +// var adPlatformKey: String { get } +// +// var adUnitID: String { get } +// +// var isReady: Bool { get } +// +// func loadAd() +// func showAd() +// +//} +// +//class VPAppOpenAdManager: NSObject { +// +// static let manager = VPAppOpenAdManager() +// +// weak var delegate: VPAppOpenAdManagerDelegate? +// +// private(set) var appOpenAd: VPAppOpenAd? { +// didSet { +// oldValue?.delegate = nil +// appOpenAd?.delegate = self +// } +// } +// +// private var isLoading = false +// private var isShowing = false +// ///允许自动展示 +// private var needAutoShow = false +// +// private var timeOutTimer: Timer? +// +// private var adsDate: Date? +// +// deinit { +// NotificationCenter.default.removeObserver(self) +// } +// +// override init() { +// super.init() +// NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) +// } +// +// func showAdIfAvailable() { +// +// if self.appOpenAd?.isReady == true { +// self.showAd() +// } else { +// self.timeOutTimer = Timer.scheduledTimer(timeInterval: 5, target: (self), selector: #selector(handleTimeOutTimer), userInfo: nil, repeats: false) +// +// self.needAutoShow = true +// self.loadAd() +// } +// } +// +// func loadAd() { +// guard !isLoading else { return } +// +// self.isLoading = true +// appOpenAd = VPApplovinAppOpenAd() +// appOpenAd?.loadAd() +// } +// +// func showAd() { +// guard self.appOpenAd?.isReady == true else { return } +// guard !self.isShowing else { return } +// +// +// self.isShowing = true +// self.appOpenAd?.showAd() +// } +// +// @objc private func handleTimeOutTimer() { +// self.needAutoShow = false +// cleanTimer() +// +// let error = NSError(domain: "time-out", code: -1) +// requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) +// self.delegate?.appOpenAdManager?(adManager: self, didOtherFail: error) +// } +// +// private func cleanTimer() { +// self.timeOutTimer?.invalidate() +// self.timeOutTimer = nil +// } +// +// private func clean() { +// appOpenAd = nil +// delegate = nil +// isShowing = false +// self.adsDate = nil +// } +//} +// +////MARK: -------------- VPAppOpenAdDelegate -------------- +//extension VPAppOpenAdManager: VPAppOpenAdDelegate { +// +// ///广告加载失败 +// func appOpenAd(ad: VPAppOpenAd, didLoadFail error: Error) { +// cleanTimer() +// isLoading = false +// requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) +// +// self.delegate?.appOpenAdManager?(adManager: self, didLoadFail: error) +// +// clean() +// } +// ///广告加载成功 +// func appOpenAdDidLoadFinish(ad: VPAppOpenAd) { +// cleanTimer() +// self.isLoading = false +// self.delegate?.appOpenAdManagerDidLoadFinish?(adManager: self) +// +// if needAutoShow { +// self.needAutoShow = false +// self.showAd() +// } +// +// } +// ///广告展示失败 +// func appOpenAd(ad: VPAppOpenAd, didDisplayFail error: Error) { +// requestStatAd(type: "show_failed", errorMsg: error.localizedDescription) +// self.delegate?.appOpenAdManager?(adManager: self, didDisplayFail: error) +// clean() +// } +// ///广告被展示 +// func appOpenAdDidShow(ad: VPAppOpenAd) { +// adsDate = Date() +// requestStatAd(type: "start", errorMsg: nil) +// self.delegate?.appOpenAdManagerDidShow?(adManager: self) +// } +// ///广告被关闭 +// func appOpenAdDidDismiss(ad: VPAppOpenAd) { +// requestStatAd(type: "close", errorMsg: nil) +// self.delegate?.appOpenAdManagerDidDismiss?(adManager: self) +// clean() +// } +// ///广告被点击 +// func appOpenAdDidClick(ad: VPAppOpenAd) { +// requestStatAd(type: "click", errorMsg: nil) +// self.delegate?.appOpenAdManagerDidClick?(adManager: self) +// } +//} +// +// +//extension VPAppOpenAdManager { +// +// private func requestStatAd(type: String, errorMsg: String?) { +// guard let appOpenAd = self.appOpenAd else { return } +// +// var seconds = 0 +// if let adsDate = self.adsDate { +// if type == "click" || type == "close" { +// seconds = Int(Date().timeIntervalSince(adsDate)) +// } +// } +// +// +// let model = VPStatAdModel() +// model.type = type +// model.view_seconds = seconds +// model.ads_id = appOpenAd.adUnitID +// model.ad_platform_key = VPAdPlatformKey(rawValue: appOpenAd.adPlatformKey) +// model.error_msg = errorMsg +// model.scene = .splash +// +//// VPStatAPI.requestStatAd(model: model) +// } +// +// +// @objc private func didEnterBackgroundNotification() { +// guard self.isShowing else { return } +// +// self.requestStatAd(type: "Interrupt", errorMsg: nil) +// } +//} diff --git a/SynthReel/Base/AdManager/AppOpen/VPApplovinAppOpenAd.swift b/SynthReel/Base/AdManager/AppOpen/VPApplovinAppOpenAd.swift new file mode 100644 index 0000000..89cc27a --- /dev/null +++ b/SynthReel/Base/AdManager/AppOpen/VPApplovinAppOpenAd.swift @@ -0,0 +1,84 @@ +//// +//// VPApplovinAppOpenAd.swift +//// Veloria +//// +//// Created by 湖南秦九 on 2025/7/15. +//// +// +//import UIKit +//#if canImport(AppLovinSDK) +//import AppLovinSDK +//#endif +// +//class VPApplovinAppOpenAd: NSObject, VPAppOpenAd { +// +// +// +// private lazy var appOpenAd = MAAppOpenAd(adUnitIdentifier: adUnitID) +// +// weak var delegate: (any VPAppOpenAdDelegate)? +// +// var adPlatformKey: String { +// return VPAdPlatformKey.applovin.rawValue +// } +// +// var adUnitID: String { +// return VPAdManager.applovin_appOpenAdUnitID +// } +// +// var isReady: Bool { +// if ALSdk.shared().isInitialized && appOpenAd.isReady { +// return true +// } else { +// return false +// } +// } +// +// func loadAd() { +// +// VPAdManager.initialize_applovinSdk { [weak self] in +// guard let self = self else { return } +// appOpenAd.delegate = self +// appOpenAd.load() +// } +// } +// +// func showAd() { +// guard isReady else { return } +// +// appOpenAd.show() +// } +//} +// +// +//extension VPApplovinAppOpenAd: MAAdDelegate { +// func didLoad(_ ad: MAAd) { +// self.delegate?.appOpenAdDidLoadFinish?(ad: self) +// } +// +// func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { +// let nsError = NSError(domain: error.message, code: error.code.rawValue) +// self.delegate?.appOpenAd?(ad: self, didLoadFail: nsError) +// } +// +// func didDisplay(_ ad: MAAd) { +// self.delegate?.appOpenAdDidShow?(ad: self) +// } +// +// func didHide(_ ad: MAAd) { +// self.delegate?.appOpenAdDidDismiss?(ad: self) +// } +// +// func didClick(_ ad: MAAd) { +// self.delegate?.appOpenAdDidClick?(ad: self) +// } +// +// func didFail(toDisplay ad: MAAd, withError error: MAError) { +// let nsError = NSError(domain: error.message, code: error.code.rawValue) +// self.delegate?.appOpenAd?(ad: self, didDisplayFail: nsError) +// } +// +// +// +//} +// diff --git a/SynthReel/Base/AdManager/Banner/VPApplovinBannerAd.swift b/SynthReel/Base/AdManager/Banner/VPApplovinBannerAd.swift new file mode 100644 index 0000000..9249e97 --- /dev/null +++ b/SynthReel/Base/AdManager/Banner/VPApplovinBannerAd.swift @@ -0,0 +1,88 @@ +//// +//// VPApplovinBannerAd.swift +//// Veloria +//// +//// Created by 湖南秦九 on 2025/7/17. +//// +// +//import UIKit +//import AppLovinSDK +// +//class VPApplovinBannerAd: NSObject, VPBannerAd { +// +// let size = CGSize.init(width: UIScreen.width, height: 59) +// +// var delegate: (any VPBannerAdDelegate)? +// +// ///是否加载过 +// private var isLoaded = false +// +// private(set) lazy var _adView: MAAdView = { +// let view = MAAdView(adUnitIdentifier: adUnitID) +// view.frame = .init(x: 0, y: 0, width: size.width, height: size.height) +// view.delegate = self +// return view +// }() +// +// var adView: UIView { +// return _adView +// } +// +// var adPlatformKey: String { +// return VPAdPlatformKey.applovin.rawValue +// } +// +// var adUnitID: String { +// return VPAdManager.applovin_bannerAdUnitID +// } +// +// func loadAd() { +// _adView.loadAd() +// } +//} +// +////MARK: -------------- MAAdViewAdDelegate -------------- +//extension VPApplovinBannerAd: MAAdViewAdDelegate { +// func didExpand(_ ad: MAAd) { +// +// } +// +// func didCollapse(_ ad: MAAd) { +// +// } +// +// func didLoad(_ ad: MAAd) { +// if !isLoaded { +// isLoaded = true +// self.delegate?.bannerAdDidLoadFinish?(bannerAd: self) +// } +// } +// +// func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { +// if !isLoaded { +// isLoaded = true +// let nsError = NSError(domain: error.message, code: error.code.rawValue) +// self.delegate?.bannerAd?(bannerAd: self, didLoadFail: nsError) +// } +// } +// +// func didDisplay(_ ad: MAAd) { +// self.delegate?.bannerAdDidShow?(bannerAd: self) +// } +// +// func didHide(_ ad: MAAd) { +// self.delegate?.bannerAdDidDismiss?(bannerAd: self) +// } +// +// func didClick(_ ad: MAAd) { +// self.delegate?.bannerAdDidClick?(ad: self) +// } +// +// func didFail(toDisplay ad: MAAd, withError error: MAError) { +// +// } +// +// +// +//} +// diff --git a/SynthReel/Base/AdManager/Banner/VPBannerAdManager.swift b/SynthReel/Base/AdManager/Banner/VPBannerAdManager.swift new file mode 100644 index 0000000..51bbcdf --- /dev/null +++ b/SynthReel/Base/AdManager/Banner/VPBannerAdManager.swift @@ -0,0 +1,131 @@ +//// +//// VPBannerAdManager.swift +//// Veloria +//// +//// Created by 湖南秦九 on 2025/7/15. +//// +// +//import UIKit +//#if canImport(AppLovinSDK) +//import AppLovinSDK +//#endif +// +// +//@objc protocol VPBannerAdDelegate: NSObjectProtocol { +// ///广告加载失败 +// @objc optional func bannerAd(bannerAd: VPBannerAd, didLoadFail error: Error) +// ///广告加载成功 +// @objc optional func bannerAdDidLoadFinish(bannerAd: VPBannerAd) +// ///广告被展示 +// @objc optional func bannerAdDidShow(bannerAd: VPBannerAd) +// ///广告被关闭 +// @objc optional func bannerAdDidDismiss(bannerAd: VPBannerAd) +// ///广告被点击 +// @objc optional func bannerAdDidClick(ad: VPBannerAd) +//} +// +//@objc protocol VPBannerAd: NSObjectProtocol { +// +// weak var delegate: VPBannerAdDelegate? { get set } +// +// var adView: UIView { get } +// +// var adPlatformKey: String { get } +// +// var adUnitID: String { get } +// +// func loadAd() +// +//} +// +//class VPBannerAdManager: NSObject { +// +// let size = CGSize.init(width: UIScreen.width, height: 59) +// +// var videoInfo: VPVideoInfoModel? +// +// private var adsDate: Date? +// +// private(set) lazy var bannerAd: VPBannerAd = { +// let ad = VPApplovinBannerAd() +// ad.delegate = self +// return ad +// }() +// +// var adView: UIView { +// return bannerAd.adView +// } +// +// deinit { +// NotificationCenter.default.removeObserver(self) +// } +// +// override init() { +// super.init() +// NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) +// +// bannerAd.loadAd() +// } +// +// +//} +// +////MARK: -------------- VPBannerAdDelegate -------------- +//extension VPBannerAdManager: VPBannerAdDelegate { +// +// ///广告加载失败 +// func bannerAd(bannerAd: VPBannerAd, didLoadFail error: Error) { +// requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) +// } +// ///广告加载成功 +// func bannerAdDidLoadFinish(bannerAd: VPBannerAd) { +// adsDate = Date() +// requestStatAd(type: "start", errorMsg: nil) +// } +// ///广告被展示 +// func bannerAdDidShow(bannerAd: VPBannerAd) { +// +// } +// ///广告被关闭 +// func bannerAdDidDismiss(bannerAd: VPBannerAd) { +// requestStatAd(type: "close", errorMsg: nil) +// } +// ///广告被点击 +// func bannerAdDidClick(ad: VPBannerAd) { +// requestStatAd(type: "click", errorMsg: nil) +// } +// +//} +// +//extension VPBannerAdManager { +// +// func requestStatAd(type: String, errorMsg: String?) { +// +// var seconds = 0 +// if let adsDate = self.adsDate { +// if type == "click" || type == "close" { +// seconds = Int(Date().timeIntervalSince(adsDate)) +// } +// } +// +// if type == "close" && self.adsDate == nil { return } +// +// let model = VPStatAdModel() +// model.view_seconds = seconds +// model.type = type +// model.ads_id = bannerAd.adUnitID +// model.ad_platform_key = VPAdPlatformKey(rawValue: bannerAd.adPlatformKey) +// model.error_msg = errorMsg +// model.scene = .banner +// model.short_play_id = self.videoInfo?.short_play_id +// model.short_play_video_id = self.videoInfo?.short_play_video_id +// +// VPStatAPI.requestStatAd(model: model) +// } +// +// +// @objc private func didEnterBackgroundNotification() { +// +// self.requestStatAd(type: "Interrupt", errorMsg: nil) +// } +//} diff --git a/SynthReel/Base/AdManager/Rewarded/VPApplovinRewardedAd.swift b/SynthReel/Base/AdManager/Rewarded/VPApplovinRewardedAd.swift new file mode 100644 index 0000000..fada746 --- /dev/null +++ b/SynthReel/Base/AdManager/Rewarded/VPApplovinRewardedAd.swift @@ -0,0 +1,91 @@ +//// +//// VPApplovinRewardedAd.swift +//// Veloria +//// +//// Created by 湖南秦九 on 2025/7/15. +//// +// +//import UIKit +//#if canImport(AppLovinSDK) +//import AppLovinSDK +//#endif +// +//class VPApplovinRewardedAd: NSObject, VPRewardedAd { +// +// +//#if canImport(AppLovinSDK) +// private var rewardedAd: MARewardedAd? +//#endif +// +// weak var delegate: (any VPRewardedAdDelegate)? +// +// var adInfo: VPAdInfo? = nil +// +// var isReady: Bool { +//#if canImport(AppLovinSDK) +// return rewardedAd?.isReady ?? false +//#else +// return false +//#endif +// } +// +// func loadAd(adInfo: VPAdInfo) { +// self.adInfo = adInfo +//#if canImport(AppLovinSDK) +// rewardedAd = MARewardedAd.shared(withAdUnitIdentifier: adInfo.ads_id ?? "") +// rewardedAd?.delegate = self +// rewardedAd?.load() +//#endif +// } +// +// func showAd() { +//#if canImport(AppLovinSDK) +// if isReady { +// rewardedAd?.show() +// } +//#endif +// } +// +// +//} +// +//#if canImport(AppLovinSDK) +////MARK: -------------- MARewardedAdDelegate -------------- +//extension VPApplovinRewardedAd: MARewardedAdDelegate { +// +// func didLoad(_ ad: MAAd) { +// self.delegate?.rewardedAdDidLoadFinish?(ad: self) +// } +// +// func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { +// +// let nsError = NSError(domain: error.message, code: error.code.rawValue) +// self.delegate?.rewardedAd?(ad: self, didLoadFail: nsError) +// } +// +// func didDisplay(_ ad: MAAd) { +// self.delegate?.rewardedAdDidShow?(ad: self) +// } +// +// func didHide(_ ad: MAAd) { +// self.delegate?.rewardedAdDidDismiss?(ad: self) +// } +// +// func didClick(_ ad: MAAd) { +// self.delegate?.rewardedAdDidClick?(ad: self) +// } +// +// func didFail(toDisplay ad: MAAd, withError error: MAError) { +// let nsError = NSError(domain: error.message, code: error.code.rawValue) +// self.delegate?.rewardedAd?(ad: self, didDisplayFail: nsError) +// } +// +// func didRewardUser(for ad: MAAd, with reward: MAReward) { +// if let adInfo = self.adInfo { +// self.delegate?.rewardedAd?(ad: self, userDidEarnReward: adInfo) +// } +// } +//} +//#endif +// +// diff --git a/SynthReel/Base/AdManager/Rewarded/VPGoogleRewardedAd.swift b/SynthReel/Base/AdManager/Rewarded/VPGoogleRewardedAd.swift new file mode 100644 index 0000000..cdbe71d --- /dev/null +++ b/SynthReel/Base/AdManager/Rewarded/VPGoogleRewardedAd.swift @@ -0,0 +1,101 @@ +//// +//// VPGoogleRewardedAd.swift +//// Veloria +//// +//// Created by 湖南秦九 on 2025/7/14. +//// +// +//import UIKit +//#if canImport(GoogleMobileAds) +//import GoogleMobileAds +//#endif +// +//class VPGoogleRewardedAd: NSObject, VPRewardedAd { +// +// +// +//#if canImport(GoogleMobileAds) +// private var rewardedAd: RewardedAd? +//#endif +// +// weak var delegate: VPRewardedAdDelegate? +// +// var adInfo: VPAdInfo? +// +// var isReady: Bool { +//#if canImport(GoogleMobileAds) +// if rewardedAd != nil { +// return true +// } else { +// return false +// } +//#else +// return false +//#endif +// } +// +// func loadAd(adInfo: VPAdInfo) { +//#if canImport(GoogleMobileAds) +// self.adInfo = adInfo +//#if DEBUG +// adInfo.ads_id = VPAdManager.google_rewardedAdUnitID +//#endif +// let adUnitID = adInfo.ads_id ?? "" +// let request = Request() +// +// RewardedAd.load(with: adUnitID, request: request) { [weak self] rewardedAd, error in +// guard let self = self else { return } +// if let error = error { +// self.delegate?.rewardedAd?(ad: self, didLoadFail: error) +// return +// } +// self.rewardedAd = rewardedAd +// self.rewardedAd?.fullScreenContentDelegate = self +// self.delegate?.rewardedAdDidLoadFinish?(ad: self) +// } +//#endif +// } +// +// func showAd() { +//#if canImport(GoogleMobileAds) +// guard let rewardedAd = rewardedAd else { return } +// +// rewardedAd.present(from: nil) { [weak self] in +// guard let self = self else { return } +// guard let adInfo = self.adInfo else { return } +// self.delegate?.rewardedAd?(ad: self, userDidEarnReward: adInfo) +// } +//#endif +// } +// +// +// +//} +// +////MARK: -------------- FullScreenContentDelegate -------------- +//#if canImport(GoogleMobileAds) +//extension VPGoogleRewardedAd: FullScreenContentDelegate { +// +// /// Tells the delegate that the ad failed to present full screen content. +// func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { +// self.delegate?.rewardedAd?(ad: self, didDisplayFail: error) +// } +// +// /// Tells the delegate that the ad will present full screen content. +// func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) { +// print("====Ad will present full screen content.") +// self.delegate?.rewardedAdDidShow?(ad: self) +// } +// +// /// Tells the delegate that the ad dismissed full screen content. +// func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) { +// print("====Ad did dismiss full screen content.") +// self.delegate?.rewardedAdDidDismiss?(ad: self) +// } +// +// func adDidRecordClick(_ ad: any FullScreenPresentingAd) { +// self.delegate?.rewardedAdDidClick?(ad: self) +// } +// +//} +//#endif diff --git a/SynthReel/Base/AdManager/Rewarded/VPRewardedAdManager.swift b/SynthReel/Base/AdManager/Rewarded/VPRewardedAdManager.swift new file mode 100644 index 0000000..731cc9c --- /dev/null +++ b/SynthReel/Base/AdManager/Rewarded/VPRewardedAdManager.swift @@ -0,0 +1,292 @@ +//// +//// VPRewardedAdManager.swift +//// Veloria +//// +//// Created by 湖南秦九 on 2025/7/14. +//// +// +//import UIKit +// +// +//@objc protocol VPRewardedAdManagerDelegate: NSObjectProtocol { +// +// ///发放奖励 +// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, userDidEarnReward adInfo: VPAdInfo) +// ///广告加载成功 +// @objc optional func rewardedAdManagerDidLoadFinish(adManager: VPRewardedAdManager) +// ///广告加载失败 +// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didLoadFail error: Error) +// ///广告展示失败 +// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didDisplayFail error: Error) +// ///广告被展示 +// @objc optional func rewardedAdManagerDidShow(adManager: VPRewardedAdManager) +// ///广告被关闭 +// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didDismiss adInfo: VPAdInfo) +// ///广告被点击 +// @objc optional func rewardedAdManagerDidClick(adManager: VPRewardedAdManager) +// ///其它错误 +// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didOtherFail error: Error) +// +//} +// +//@objc protocol VPRewardedAdDelegate: NSObjectProtocol { +// +// ///发放奖励 +// @objc optional func rewardedAd(ad: VPRewardedAd, userDidEarnReward adInfo: VPAdInfo) +// ///广告加载失败 +// @objc optional func rewardedAd(ad: VPRewardedAd, didLoadFail error: Error) +// ///广告加载成功 +// @objc optional func rewardedAdDidLoadFinish(ad: VPRewardedAd) +// ///广告展示失败 +// @objc optional func rewardedAd(ad: VPRewardedAd, didDisplayFail error: Error) +// ///广告被展示 +// @objc optional func rewardedAdDidShow(ad: VPRewardedAd) +// ///广告被关闭 +// @objc optional func rewardedAdDidDismiss(ad: VPRewardedAd) +// ///广告被点击 +// @objc optional func rewardedAdDidClick(ad: VPRewardedAd) +//} +// +//@objc protocol VPRewardedAd: NSObjectProtocol { +// +// weak var delegate: VPRewardedAdDelegate? { get set } +// var adInfo: VPAdInfo? { get set } +// var isReady: Bool { get } +// +// func loadAd(adInfo: VPAdInfo) +// func showAd() +// +//} +// +//class VPRewardedAdManager: NSObject { +// +// static let manager = VPRewardedAdManager() +// +// private weak var delegate: VPRewardedAdManagerDelegate? +// +// ///广告在加载中 +// private var isLoadingAd = false +// ///广告激活状态 +// private(set) var isEnable = true +// +// private var adInfo: VPAdInfo? +// +// private var adsDate: Date? +// ///统计场景 +// var statScene: VPStatAdModel.AdScene? +// var videoInfo: VPVideoInfoModel? +// +// var rewardedAd: VPRewardedAd? { +// didSet { +// rewardedAd?.delegate = self +// } +// } +// +// var isReady: Bool { +// return rewardedAd?.isReady ?? false +// } +// +// deinit { +// NotificationCenter.default.removeObserver(self) +// } +// +// override init() { +// super.init() +// NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) +// } +// +// func loadAd() { +// if isReady || isLoadingAd { return } +// +// self.isLoadingAd = true +// +// self.getAdInfo { [weak self] adInfo in +// guard let self = self else { return } +// +// switch adInfo.platform_key { +// case .google: +// let ad = VPGoogleRewardedAd() +// self.rewardedAd = ad +// ad.loadAd(adInfo: adInfo) +// +// case .applovin: +// let ad = VPApplovinRewardedAd() +// self.rewardedAd = ad +// ad.loadAd(adInfo: adInfo) +// +// default: +// self.adInfo = nil +// break +// } +// } +// +// } +// +// func showAd(delegate: VPRewardedAdManagerDelegate? = nil) { +// if isEnable && !isLoadingAd && !isReady {//没有任何广告,并且没有正在加载的广告,需要出发加载广告 +// loadAd() +// } +// +// if !isEnable || !isReady { +// VPToast.show(text: "veloria_no_ads_tip".localized) +// let error = NSError(domain: "veloria_no_ads_tip".localized, code: -1) +// self.delegate?.rewardedAdManager?(adManager: self, didOtherFail: error) +// return +// } +// +// guard let rewardedAd = self.rewardedAd else { return } +// self.delegate = delegate +// +// rewardedAd.showAd() +// } +// +// private func clean() { +// self.rewardedAd = nil +// self.statScene = nil +// self.videoInfo = nil +// self.delegate = nil +// } +//} +// +////MARK: -------------- VPRewardedAdDelegate -------------- +//extension VPRewardedAdManager: VPRewardedAdDelegate { +// +// ///发放奖励 +// func rewardedAd(ad: VPRewardedAd, userDidEarnReward adInfo: VPAdInfo) { +// self.requestStatAd(type: "reward", errorMsg: nil) +// self.delegate?.rewardedAdManager?(adManager: self, userDidEarnReward: adInfo) +// } +// ///广告加载失败 +// func rewardedAd(ad: VPRewardedAd, didLoadFail error: Error) { +// isEnable = false +// isLoadingAd = false +// +// self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) +// self.delegate?.rewardedAdManager?(adManager: self, didLoadFail: error) +// +// self.clean() +// } +// ///广告加载成功 +// func rewardedAdDidLoadFinish(ad: VPRewardedAd) { +// isLoadingAd = false +// +// self.delegate?.rewardedAdManagerDidLoadFinish?(adManager: self) +// } +// ///广告展示失败 +// func rewardedAd(ad: VPRewardedAd, didDisplayFail error: Error) { +// +// self.requestStatAd(type: "show_failed", errorMsg: error.localizedDescription) +// self.delegate?.rewardedAdManager?(adManager: self, didDisplayFail: error) +// +// self.isEnable = false +// self.clean() +// +// /* +// if self.adInfo?.platform_key != .google { +// let adInfo = VPAdInfo() +// adInfo.platform_key = .google +// adInfo.ads_id = VPAdManager.google_rewardedAdUnitID +// +// let ad = VPGoogleRewardedAd() +// self.rewardedAd = ad +// ad.loadAd(adInfo: adInfo) +// +// } else { +// self.isEnable = false +// } +// */ +// +// } +// ///广告被展示 +// func rewardedAdDidShow(ad: VPRewardedAd) { +// self.adsDate = Date() +// +// self.requestStatAd(type: "start", errorMsg: nil) +// self.delegate?.rewardedAdManagerDidShow?(adManager: self) +// } +// ///广告被关闭 +// func rewardedAdDidDismiss(ad: VPRewardedAd) { +// +// +// var seconds = 0 +// if let adsDate = self.adsDate { +// seconds = Int(Date().timeIntervalSince(adsDate)) +// } +// +// +// self.requestStatAd(type: "close", seconds: seconds, errorMsg: nil) { [weak self] in +// guard let self = self else { return } +// if let adInfo = ad.adInfo { +// self.delegate?.rewardedAdManager?(adManager: self, didDismiss: adInfo) +// } +// +// self.clean() +// //加载新的广告 +// self.loadAd() +// } +// +// } +// +// ///广告被点击 +// func rewardedAdDidClick(ad: VPRewardedAd) { +// +// var seconds = 0 +// if let adsDate = self.adsDate { +// seconds = Int(Date().timeIntervalSince(adsDate)) +// } +// self.requestStatAd(type: "click", seconds: seconds, errorMsg: nil) +// +// self.delegate?.rewardedAdManagerDidClick?(adManager: self) +// } +// +//} +// +// +//extension VPRewardedAdManager { +// private func requestStatAd(type: String, seconds: Int = 0, errorMsg: String?, completer: (() -> Void)? = nil) { +// guard let adInfo = adInfo else { return } +// +// let model = VPStatAdModel() +// model.type = type +// model.ads_id = adInfo.ads_id +// model.view_seconds = seconds +// model.ad_platform_key = adInfo.platform_key +// model.error_msg = errorMsg +// model.scene = self.statScene +// model.short_play_id = self.videoInfo?.short_play_id +// model.short_play_video_id = self.videoInfo?.short_play_video_id +// +// VPStatAPI.requestStatAd(model: model) { finish in +// completer?() +// } +// } +// +// @objc private func didEnterBackgroundNotification() { +// if self.statScene == nil { return } +// +// self.requestStatAd(type: "Interrupt", seconds: 0, errorMsg: nil) +// } +// +// +// private func getAdInfo(completer: ((_ adInfo: VPAdInfo) -> Void)?) { +// +// if let adInfo = self.adInfo { +// completer?(adInfo) +// } +// VPAdAPI.requestShowAdInfo { [weak self] adInfo in +// guard let self = self else { return } +// +// if let adInfo = adInfo { +// self.adInfo = adInfo +// completer?(adInfo) +// } else { +// let adInfo = VPAdInfo.createNormalAdInfo() +// self.adInfo = adInfo +// completer?(adInfo) +// } +// +// } +// } +//} +// +// diff --git a/SynthReel/Base/AdManager/VPAdInfo.swift b/SynthReel/Base/AdManager/VPAdInfo.swift new file mode 100644 index 0000000..a4e07ce --- /dev/null +++ b/SynthReel/Base/AdManager/VPAdInfo.swift @@ -0,0 +1,40 @@ +// +// VPAdInfo.swift +// Veloria +// +// Created by 湖南秦九 on 2025/7/14. +// + +import UIKit +import SmartCodable + +enum VPAdPlatformKey: String, SmartCaseDefaultable { + case google = "google" + case applovin = "applovin" +} + +struct VPAdDataModel: SmartCodable { + var ad: VPAdInfo? +} + +class VPAdInfo:NSObject, SmartCodable { + + required override init() { + super.init() + } + + var id: String? + var platform_name: String? + var ads_id: String? + var status: String? + var platform_key: VPAdPlatformKey? + + + static func createNormalAdInfo() -> VPAdInfo { + var adInfo = VPAdInfo() + adInfo.platform_key = .applovin + adInfo.ads_id = VPAdManager.applovin_rewardedAdUnitID + return adInfo + } + +} diff --git a/SynthReel/Base/AdManager/VPAdManager.swift b/SynthReel/Base/AdManager/VPAdManager.swift new file mode 100644 index 0000000..9be29c6 --- /dev/null +++ b/SynthReel/Base/AdManager/VPAdManager.swift @@ -0,0 +1,100 @@ +// +// VPAdManager.swift +// Veloria +// +// Created by 湖南秦九 on 2025/7/14. +// + +import UIKit +#if canImport(GoogleMobileAds) +import GoogleMobileAds +#endif +#if canImport(AppLovinSDK) +import AppLovinSDK +#endif + +class VPAdManager: NSObject { + + + static var completer: (() -> Void)? + + static func start() { +#if canImport(GoogleMobileAds) + MobileAds.shared.start() +#endif + + initialize_applovinSdk() + } + + ///初始化AppLovinSDK + static func initialize_applovinSdk(completer: (() -> Void)? = nil) { + if completer != nil { + self.completer = completer + } +#if canImport(AppLovinSDK) + if !ALSdk.shared().isInitialized { + //初始化 + let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in + builder.mediationProvider = ALMediationProviderMAX +//#if DEBUG +// builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()] +//#endif + } + + ALSdk.shared().initialize(with: initConfig) { sdkConfig in + // Start loading ads + self.completer?() + } + } else { + self.completer?() + } +#endif + } + +} + +//MARK: -------------- 单元ID -------------- +extension VPAdManager { + + ///谷歌激励广告单元ID + static var google_rewardedAdUnitID: String { +#if DEBUG + return "ca-app-pub-3940256099942544/1712485313" +#else + return "" +#endif + } + + ///开屏广告的单元ID + static var google_appOpenAdUnitID: String { +#if DEBUG + return "ca-app-pub-3940256099942544/5575463023" +#else + return "" +#endif + } + ///横幅广告单元ID + static var google_bannerAdUnitID: String { +#if DEBUG + return "ca-app-pub-3940256099942544/2435281174" +#else + return "" +#endif + } + + ///激励广告的单元ID + static var applovin_rewardedAdUnitID: String { + return "39bf981e27728eae" + } + + ///开屏广告的单元ID + static var applovin_appOpenAdUnitID: String { + return "d587df0fd75ff03b" + } + ///横幅广告单元ID + static var applovin_bannerAdUnitID: String { + return "1eb6278843149711" + } + + +} diff --git a/SynthReel/Base/AdManager/VPStatAdModel.swift b/SynthReel/Base/AdManager/VPStatAdModel.swift new file mode 100644 index 0000000..a746644 --- /dev/null +++ b/SynthReel/Base/AdManager/VPStatAdModel.swift @@ -0,0 +1,33 @@ +// +// VPStatAdModel.swift +// Veloria +// +// Created by 湖南秦九 on 2025/7/14. +// + +import UIKit +import SmartCodable + +class VPStatAdModel: NSObject, SmartCodable { + + required override init() { + super.init() + } + + enum AdScene: String, SmartCaseDefaultable { + case detail = "detail" + case me = "me" + case reward = "reward" + case splash = "splash" + case banner = "banner" + } + + var type: String? //start click error click show_failed load_failed Interrupt(退到后台) close + var ads_id: String? + var view_seconds: Int? + var ad_platform_key: VPAdPlatformKey? + var scene: AdScene? // splash reward banner detail me turntable + var short_play_id: String? + var short_play_video_id: String? + var error_msg: String? +} diff --git a/SynthReel/Base/Admanger/BannerAd/SRAdmobOpenAd.swift b/SynthReel/Base/Admanger/BannerAd/SRAdmobOpenAd.swift new file mode 100644 index 0000000..caf104d --- /dev/null +++ b/SynthReel/Base/Admanger/BannerAd/SRAdmobOpenAd.swift @@ -0,0 +1,137 @@ +// +// SRAdmobOpenAd.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/11. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit +#if canImport(GoogleMobileAds) +import GoogleMobileAds +#endif + +class SRAdmobOpenAd: NSObject, SRAppOpenAd { + + #if canImport(GoogleMobileAds) + private var appOpenAd: AppOpenAd? + #endif + + weak var delegate: SRAppOpenAdDelegate? + + var adInfo: VPAdInfo? + var isShowingAd: Bool = false + + // 实现 SRAppOpenAd 协议中的 adPlatformKey 属性 + var adPlatformKey: String { + return "AdMob" // 这里可以改成适合你应用的广告平台标识 + } + + var isReady: Bool { + #if canImport(GoogleMobileAds) + return appOpenAd != nil + #else + return false + #endif + } + + // 实现 SRAppOpenAd 协议中的 adUnitID 属性 + var adUnitID: String { + return adInfo?.ads_id ?? "" + } + + // 加载广告 + func loadAd() { + #if canImport(GoogleMobileAds) + guard let adInfo = self.adInfo else { return } + + let adUnitID = adInfo.ads_id ?? "" + let request = Request() + + AppOpenAd.load(with: adUnitID, request: request) { [weak self] appOpenAd, error in + guard let self = self else { return } + + if let error = error { + self.delegate?.appOpenAd?(ad: self, didLoadFail: error) + return + } + + self.appOpenAd = appOpenAd + appOpenAd?.fullScreenContentDelegate = self + if let error = error { + self.delegate?.appOpenAd?(ad: self, didLoadFail: error) + } else { + // 如果没有错误,调用加载成功的回调 + self.delegate?.appOpenAdDidLoadFinish?(ad: self) + } + } + #endif + } + + // 显示广告 + func showAd() { + #if canImport(GoogleMobileAds) + guard let appOpenAd = appOpenAd else { + print("App open ad is not ready yet.") + return + } + + if isShowingAd { + return print("App open ad is already showing.") + } + + appOpenAd.present(from: nil) + isShowingAd = true + #endif + } +} + +// MARK: - FullScreenContentDelegate +#if canImport(GoogleMobileAds) +extension SRAdmobOpenAd: FullScreenContentDelegate { + + func adDidRecordImpression(_ ad: FullScreenPresentingAd) { + print("App open ad recorded an impression.") + delegate?.appOpenAdDidShow?(ad: self) + } + + func adDidRecordClick(_ ad: FullScreenPresentingAd) { + print("App open ad recorded a click.") + delegate?.appOpenAdDidClick?(ad: self) + } + + func adWillDismissFullScreenContent(_ ad: FullScreenPresentingAd) { + print("App open ad will be dismissed.") + } + + func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) { + print("App open ad will be presented.") + delegate?.appOpenAdDidShow?(ad: self) + } + + func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) { + print("App open ad was dismissed.") + + // 确保调用正确的委托方法 + delegate?.appOpenAdDidDismiss?(ad: self) + + appOpenAd = nil + isShowingAd = false + + // 重新加载广告 + + loadAd() + + } + + func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { + print("App open ad failed to present with error: \(error.localizedDescription)") + appOpenAd = nil + isShowingAd = false + delegate?.appOpenAd?(ad: self, didDisplayFail: error) + // 重新加载广告 + loadAd() + + } +} +#endif diff --git a/SynthReel/Base/Admanger/OpenAd/SROpenAdManager.swift b/SynthReel/Base/Admanger/OpenAd/SROpenAdManager.swift new file mode 100644 index 0000000..4212b77 --- /dev/null +++ b/SynthReel/Base/Admanger/OpenAd/SROpenAdManager.swift @@ -0,0 +1,227 @@ +//// +//// SROpenAdManager.swift +//// SynthReel +//// +//// Created by 澜声世纪 on 2025/12/10. +//// Copyright © 2025 SR. All rights reserved. +//// +// +import UIKit +import Foundation +import GoogleMobileAds + +@objc protocol SRAppOpenAdManagerDelegate: NSObjectProtocol { + + ///广告加载成功 + @objc optional func appOpenAdManagerDidLoadFinish(adManager: SRAppOpenAdDelegate) + ///广告加载失败 + @objc optional func appOpenAdManager(adManager: SRAppOpenAdDelegate, didLoadFail error: Error) + ///广告展示失败 + @objc optional func appOpenAdManager(adManager: SRAppOpenAdDelegate, didDisplayFail error: Error) + ///广告被展示 + @objc optional func appOpenAdManagerDidShow(adManager: SRAppOpenAdDelegate) + ///广告被关闭 + @objc optional func appOpenAdManagerDidDismiss(adManager: SRAppOpenAdDelegate) + ///广告被点击 + @objc optional func appOpenAdManagerDidClick(adManager: SRAppOpenAdDelegate) + ///其它错误 + @objc optional func appOpenAdManager(adManager: SRAppOpenAdDelegate, didOtherFail error: Error) + +} + + +@objc protocol SRAppOpenAdDelegate: NSObjectProtocol { + + ///广告加载失败 + @objc optional func appOpenAd(ad: SRAppOpenAd, didLoadFail error: Error) + ///广告加载成功 + @objc optional func appOpenAdDidLoadFinish(ad: SRAppOpenAd) + ///广告展示失败 + @objc optional func appOpenAd(ad: SRAppOpenAd, didDisplayFail error: Error) + ///广告被展示 + @objc optional func appOpenAdDidShow(ad: SRAppOpenAd) + ///广告被关闭 + @objc optional func appOpenAdDidDismiss(ad: SRAppOpenAd) + ///广告被点击 + @objc optional func appOpenAdDidClick(ad: SRAppOpenAd) +} + +@objc protocol SRAppOpenAd: NSObjectProtocol { + + weak var delegate: SRAppOpenAdDelegate? { get set } + + var adPlatformKey: String { get } + + var adUnitID: String { get } + + var isReady: Bool { get } + + func loadAd() + func showAd() + +} + +class SRAppOpenAdManager: NSObject { + + static let manager = SRAppOpenAdManager() + + weak var delegate: SRAppOpenAdManagerDelegate? + + private(set) var appOpenAd: SRAppOpenAd? { + didSet { + oldValue?.delegate = nil + appOpenAd?.delegate = self + } + } + + private var isLoading = false + private var isShowing = false + ///允许自动展示 + private var needAutoShow = false + + private var timeOutTimer: Timer? + + private var adsDate: Date? + + deinit { + NotificationCenter.default.removeObserver(self) + } + + override init() { + super.init() + NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) + } + + func showAdIfAvailable() { + + if self.appOpenAd?.isReady == true { + self.showAd() + } else { + self.timeOutTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(handleTimeOutTimer), userInfo: nil, repeats: false) + + self.needAutoShow = true + self.loadAd() + } + } + + func loadAd() { + guard !isLoading else { return } + + self.isLoading = true + appOpenAd = SRAdmobOpenAd() + appOpenAd?.loadAd() + } + + func showAd() { + guard self.appOpenAd?.isReady == true else { return } + guard !self.isShowing else { return } + + + self.isShowing = true + self.appOpenAd?.showAd() + } + + @objc private func handleTimeOutTimer() { + self.needAutoShow = false + cleanTimer() + + let error = NSError(domain: "time-out", code: -1) + requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) + self.delegate?.appOpenAdManager?(adManager: self, didOtherFail: error) + } + + private func cleanTimer() { + self.timeOutTimer?.invalidate() + self.timeOutTimer = nil + } + + private func clean() { + appOpenAd = nil + delegate = nil + isShowing = false + self.adsDate = nil + } +} + +//MARK: -------------- VPAppOpenAdDelegate -------------- +extension SRAppOpenAdManager: SRAppOpenAdDelegate { + + ///广告加载失败 + func appOpenAd(ad: SRAppOpenAd, didLoadFail error: Error) { + cleanTimer() + isLoading = false + requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) + + self.delegate?.appOpenAdManager?(adManager: self, didLoadFail: error) + + clean() + } + ///广告加载成功 + func appOpenAdDidLoadFinish(ad: SRAppOpenAd) { + cleanTimer() + self.isLoading = false + self.delegate?.appOpenAdManagerDidLoadFinish?(adManager: self) + + if needAutoShow { + self.needAutoShow = false + self.showAd() + } + + } + ///广告展示失败 + func appOpenAd(ad: SRAppOpenAd, didDisplayFail error: Error) { + requestStatAd(type: "show_failed", errorMsg: error.localizedDescription) + self.delegate?.appOpenAdManager?(adManager: self, didDisplayFail: error) + clean() + } + ///广告被展示 + func appOpenAdDidShow(ad: SRAppOpenAd) { + adsDate = Date() + requestStatAd(type: "start", errorMsg: nil) + self.delegate?.appOpenAdManagerDidShow?(adManager: self) + } + ///广告被关闭 + func appOpenAdDidDismiss(ad: SRAppOpenAd) { + requestStatAd(type: "close", errorMsg: nil) + self.delegate?.appOpenAdManagerDidDismiss?(adManager: self) + clean() + } + ///广告被点击 + func appOpenAdDidClick(ad: SRAppOpenAd) { + requestStatAd(type: "click", errorMsg: nil) + self.delegate?.appOpenAdManagerDidClick?(adManager: self) + } +} + + +extension SRAppOpenAdManager { + + private func requestStatAd(type: String, errorMsg: String?) { + guard let appOpenAd = self.appOpenAd else { return } + + var seconds = 0 + if let adsDate = self.adsDate { + if type == "click" || type == "close" { + seconds = Int(Date().timeIntervalSince(adsDate)) + } + } + + + let model = VPStatAdModel() + model.type = type + model.view_seconds = seconds + model.ads_id = appOpenAd.adUnitID + model.ad_platform_key = VPAdPlatformKey(rawValue: appOpenAd.adPlatformKey) + model.error_msg = errorMsg + model.scene = .splash + +// VPStatAPI.requestStatAd(model: model) + } + + + @objc private func didEnterBackgroundNotification() { + guard self.isShowing else { return } + + self.requestStatAd(type: "Interrupt", errorMsg: nil) + } +} diff --git a/SynthReel/Base/Admanger/SRAdManger.swift b/SynthReel/Base/Admanger/SRAdManger.swift new file mode 100644 index 0000000..212d856 --- /dev/null +++ b/SynthReel/Base/Admanger/SRAdManger.swift @@ -0,0 +1,101 @@ +// +// SRAdManger.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/11. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit +#if canImport(GoogleMobileAds) +import GoogleMobileAds +#endif +#if canImport(AppLovinSDK) +import AppLovinSDK +#endif + +class SRAdManger: NSObject { + + + static var completer: (() -> Void)? + + static func start() { +#if canImport(GoogleMobileAds) + MobileAds.shared.start() +#endif + + initialize_applovinSdk() + } + + ///初始化AppLovinSDK + static func initialize_applovinSdk(completer: (() -> Void)? = nil) { + if completer != nil { + self.completer = completer + } +#if canImport(AppLovinSDK) + if !ALSdk.shared().isInitialized { + //初始化 + let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in + builder.mediationProvider = ALMediationProviderMAX +//#if DEBUG +// builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()] +//#endif + } + + ALSdk.shared().initialize(with: initConfig) { sdkConfig in + // Start loading ads + self.completer?() + } + } else { + self.completer?() + } +#endif + } + +} + +//MARK: -------------- 单元ID -------------- +extension SRAdManger { + + ///谷歌激励广告单元ID + static var google_rewardedAdUnitID: String { +#if DEBUG + return "ca-app-pub-3940256099942544/1712485313" +#else + return "ca-app-pub-6275401933109862/2121481439" +#endif + } + + ///开屏广告的单元ID + static var google_appOpenAdUnitID: String { +#if DEBUG + return "ca-app-pub-3940256099942544/5575463023" +#else + return "ca-app-pub-6275401933109862/7130265535" +#endif + } + ///横幅广告单元ID + static var google_bannerAdUnitID: String { +#if DEBUG + return "ca-app-pub-3940256099942544/2435281174" +#else + return "ca-app-pub-6275401933109862/7971191024" +#endif + } + + ///激励广告的单元ID + static var applovin_rewardedAdUnitID: String { + return "3708ac6b6026e375" + } + +// ///开屏广告的单元ID +// static var applovin_appOpenAdUnitID: String { +// return "d587df0fd75ff03b" +// } +// ///横幅广告单元ID +// static var applovin_bannerAdUnitID: String { +// return "1eb6278843149711" +// } + + +} diff --git a/SynthReel/Base/Model/SRVersionUpdateModel.swift b/SynthReel/Base/Model/SRVersionUpdateModel.swift new file mode 100644 index 0000000..518c3ec --- /dev/null +++ b/SynthReel/Base/Model/SRVersionUpdateModel.swift @@ -0,0 +1,39 @@ +// +// SRVersionUpdateModel.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/10. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit +import SmartCodable + +struct SRVersionUpdateModel: SmartCodable { + + var version_code: String? + var des: String? + var version_name: String? + + var force: Bool? + + + func canUpdate() -> Bool { + guard let version = version_code else { return false } + + let result = kSRAPPVersion.compare(version, options: .numeric) + if result == .orderedAscending { + return true + } else { + return false + } + } + + + static func mappingForKey() -> [SmartKeyTransformer]? { + return [ + CodingKeys.des <--- ["description"] + ] + } + +} diff --git a/SynthReel/Base/Networking/SRNetwork.swift b/SynthReel/Base/Networking/SRNetwork.swift index f974757..10ea7aa 100644 --- a/SynthReel/Base/Networking/SRNetwork.swift +++ b/SynthReel/Base/Networking/SRNetwork.swift @@ -49,11 +49,15 @@ class SRNetwork: NSObject { static func _request(parameters: SRNetwork.Parameters, completion: ((_ response: SRNetwork.Response) -> Void)?) -> Cancellable { if parameters.isLoding { - SRHud.show() + DispatchQueue.main.async { + SRHud.show() + } } return provider.request(.request(parameters: parameters)) { result in if parameters.isLoding { - SRHud.dismiss() + DispatchQueue.main.async { + SRHud.dismiss() + } } guard let completion = completion else {return} _resultDispose(parameters: parameters, result: result, completion: completion) diff --git a/SynthReel/Base/View/SRNavgationTitleView.swift b/SynthReel/Base/View/SRNavgationTitleView.swift index 44b2bd8..062e52e 100644 --- a/SynthReel/Base/View/SRNavgationTitleView.swift +++ b/SynthReel/Base/View/SRNavgationTitleView.swift @@ -26,7 +26,7 @@ class SRNavgationTitleView: UIView { private let titleLabel: UILabel = { let label = UILabel() - label.font = .font(ofSize: 18, weight: .bold) + label.font = .font(ofSize: 18, weight: .bold).withBoldItalic() label.textAlignment = .center label.textColor = .white return label diff --git a/SynthReel/Base/ViewController/SRAppOpenAdViewController.swift b/SynthReel/Base/ViewController/SRAppOpenAdViewController.swift new file mode 100644 index 0000000..bd93963 --- /dev/null +++ b/SynthReel/Base/ViewController/SRAppOpenAdViewController.swift @@ -0,0 +1,53 @@ +// +// SRAppOpenAdViewController.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/11. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit + +class SRAppOpenAdViewController: SRViewController { + + var didEndBlock: (() -> Void)? + + private(set) lazy var lanuchVC: UIViewController? = { + let vc = SRTool.lanuchViewController + return vc + }() + + override func viewDidLoad() { + super.viewDidLoad() + if let vc = lanuchVC { + addChild(vc) + view.addSubview(vc.view) + } + let manager = SRAppOpenAdManager.manager + manager.delegate = self + manager.showAdIfAvailable() + + } + +} + +//MARK: -------------- VPAppOpenAdManagerDelegate -------------- +extension SRAppOpenAdViewController: SRAppOpenAdManagerDelegate { + + func appOpenAdManagerDidDismiss(adManager: SRAppOpenAdDelegate) { + self.didEndBlock?() + } + + func appOpenAdManager(adManager: SRAppOpenAdDelegate, didLoadFail error: any Error) { + self.didEndBlock?() + } + + func appOpenAdManager(adManager: SRAppOpenAdDelegate, didDisplayFail error: any Error) { + self.didEndBlock?() + } + + func appOpenAdManager(adManager: SRAppOpenAdDelegate, didOtherFail error: any Error) { + self.didEndBlock?() + } + +} diff --git a/SynthReel/Base/ViewController/SRTabBarController.swift b/SynthReel/Base/ViewController/SRTabBarController.swift index f6d7faa..61b9b4d 100644 --- a/SynthReel/Base/ViewController/SRTabBarController.swift +++ b/SynthReel/Base/ViewController/SRTabBarController.swift @@ -32,6 +32,9 @@ class SRTabBarController: ESTabBarController { self.tabBar.standardAppearance = appearance self.tabBar.scrollEdgeAppearance = appearance self.tabBar.isTranslucent = false + + +// SRTool.checkUpdates() } diff --git a/SynthReel/Class/MyShort/V/SRFavoritesCell.swift b/SynthReel/Class/MyShort/V/SRFavoritesCell.swift index 3c6560f..a2f92f6 100644 --- a/SynthReel/Class/MyShort/V/SRFavoritesCell.swift +++ b/SynthReel/Class/MyShort/V/SRFavoritesCell.swift @@ -35,22 +35,24 @@ class SRFavoritesCell: UICollectionViewCell { let videoId = (self.model)?.short_play_video_id let isCollect = false -// Task { -// await SRShortApi.requestShortCollect(shortId: shortId, videoId: videoId, isCollect: isCollect) -// } - Task { - let success = await SRShortApi.requestShortCollect( - shortId: shortId, - videoId: videoId, - isCollect: isCollect - ) - - if success { - self.onCollectChanged?(self) - } else { - print("收藏失败") + let view = SRRemoveCollectAlert() + view.clickHighlightButton = { + Task { + let success = await SRShortApi.requestShortCollect( + shortId: shortId, + videoId: videoId, + isCollect: isCollect + ) + + if success { + self.onCollectChanged?(self) + } else { + print("收藏失败") + } } } + view.show() + })) button.setImage(UIImage(named: "collect_icon_01_selected"), for: .normal) button.setImage(UIImage(named: "collect_icon_01_selected"), for: .selected) diff --git a/SynthReel/Class/Player/V/SRShortDetailControlView.swift b/SynthReel/Class/Player/V/SRShortDetailControlView.swift index 4543a3f..32858b4 100644 --- a/SynthReel/Class/Player/V/SRShortDetailControlView.swift +++ b/SynthReel/Class/Player/V/SRShortDetailControlView.swift @@ -105,10 +105,29 @@ class SRShortDetailControlView: JXPlayerListControlView { guard let shortId = self.shortModel?.short_play_id else { return } let videoId = (self.model as? SRVideoInfoModel)?.short_play_video_id let isCollect = !(self.shortModel?.is_collect ?? false) - - Task { - await SRShortApi.requestShortCollect(shortId: shortId, videoId: videoId, isCollect: isCollect) + + if !isCollect { + let view = SRRemoveCollectAlert() + view.clickHighlightButton = { + Task { + let success = await SRShortApi.requestShortCollect( + shortId: shortId, + videoId: videoId, + isCollect: isCollect + ) + if success { + } else { + print("收藏失败") + } + } + } + view.show() + }else{ + Task { + await SRShortApi.requestShortCollect(shortId: shortId, videoId: videoId, isCollect: isCollect) + } } + })) button.setImage(UIImage(named: "collect_icon_01"), for: .normal) button.setImage(UIImage(named: "collect_icon_01_selected"), for: .selected) diff --git a/SynthReel/Class/Player/V/SRVideoLockView.swift b/SynthReel/Class/Player/V/SRVideoLockView.swift index 83a48e8..ecf261e 100644 --- a/SynthReel/Class/Player/V/SRVideoLockView.swift +++ b/SynthReel/Class/Player/V/SRVideoLockView.swift @@ -99,22 +99,23 @@ extension SRVideoLockView { addSubview(unlockStackView) unlockStackView.addArrangedSubview(unlockButton) - unlockStackView.addArrangedSubview(adlockButton) +// 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.height.equalTo(43 * 2 + 30) // 两个按钮 + 间距 make.centerY.equalToSuperview() // 可自定义 + make.height.equalTo(43) } unlockButton.snp.makeConstraints { make in make.height.equalTo(43) } - adlockButton.snp.makeConstraints { make in - make.height.equalTo(43) - } +// adlockButton.snp.makeConstraints { make in +// make.height.equalTo(43) +// } } } diff --git a/SynthReel/Class/User/VC/SRAboutUsController.swift b/SynthReel/Class/User/VC/SRAboutUsController.swift index fc575dc..4b5091d 100644 --- a/SynthReel/Class/User/VC/SRAboutUsController.swift +++ b/SynthReel/Class/User/VC/SRAboutUsController.swift @@ -32,10 +32,14 @@ class SRAboutUsController: SRViewController { override func viewDidLoad() { super.viewDidLoad() - self.title = "About".localized - sr_setupLayout() } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.isNavigationBarHidden = false + navigationController?.sr_setNavigationTitle("About".localized, for: self) + } } diff --git a/SynthReel/Class/User/VC/SRUserListViewController.swift b/SynthReel/Class/User/VC/SRUserListViewController.swift index ac30b4b..b9f6f1c 100644 --- a/SynthReel/Class/User/VC/SRUserListViewController.swift +++ b/SynthReel/Class/User/VC/SRUserListViewController.swift @@ -71,6 +71,7 @@ extension SRUserListViewController { var arr = [ SRUserSettingModel(type: .feedback, name: "synthreel_feedback".localized, icon: UIImage(named: "icon_feedback")), SRUserSettingModel(type: .deleteAccount, name: "synthreel_delet_account".localized, icon: UIImage(named: "icon_delet")), + SRUserSettingModel(type: .orderRecord, name: "synthreel_order_Record".localized, icon: UIImage(named: "icon_order")), 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")), @@ -116,6 +117,10 @@ extension SRUserListViewController: UITableViewDelegate, UITableViewDataSource { case .logout: logout() break + case .orderRecord: + let vc = SRWalletViewController() + self.navigationController?.pushViewController(vc, animated: true) + break case .deleteAccount: deleteAccount() break @@ -138,9 +143,13 @@ extension SRUserListViewController: UITableViewDelegate, UITableViewDataSource { } func logout(){ - Task{ - await SRLogin.manager.logout(completer: nil) + let view = SRLogoutAlert(); + view.clickHighlightButton = { + Task{ + await SRLogin.manager.logout(completer: nil) + } } + view.show() } func deleteAccount() { diff --git a/SynthReel/Class/User/model/SRUserSettingModel.swift b/SynthReel/Class/User/model/SRUserSettingModel.swift index 7e615d1..4466d42 100644 --- a/SynthReel/Class/User/model/SRUserSettingModel.swift +++ b/SynthReel/Class/User/model/SRUserSettingModel.swift @@ -18,6 +18,7 @@ struct SRUserSettingModel { case userAgreement case visitWebsite case login + case orderRecord case logout // ///消费记录 case consumptionRecords diff --git a/SynthReel/Class/wallet/VC/SRWalletViewController.swift b/SynthReel/Class/wallet/VC/SRWalletViewController.swift new file mode 100644 index 0000000..26248c4 --- /dev/null +++ b/SynthReel/Class/wallet/VC/SRWalletViewController.swift @@ -0,0 +1,29 @@ +// +// SRWalletViewController.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/10. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit + +class SRWalletViewController: SRViewController { + + override func viewDidLoad() { + super.viewDidLoad() + sr_setupLayout() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.isNavigationBarHidden = false + navigationController?.sr_setNavigationTitle("synthreel_my_wallet".localized, for: self) + } +} + +extension SRWalletViewController { + func sr_setupLayout() { + + } +} diff --git a/SynthReel/Delegate/AppDelegate+SRAPNS.swift b/SynthReel/Delegate/AppDelegate+SRAPNS.swift index 7029b14..7ed9981 100644 --- a/SynthReel/Delegate/AppDelegate+SRAPNS.swift +++ b/SynthReel/Delegate/AppDelegate+SRAPNS.swift @@ -57,7 +57,6 @@ extension SceneDelegate { // if date.fa_isToday { return } // UserDefaults.standard.set(Date(), forKey: kFAApnsAlertDefaultsKey) // #endif - // let view = SRApnsAlert() // view.show() } diff --git a/SynthReel/Libs/Alert/SRApnsAlert.swift b/SynthReel/Libs/Alert/SRApnsAlert.swift index 9d41b82..b0d4db8 100644 --- a/SynthReel/Libs/Alert/SRApnsAlert.swift +++ b/SynthReel/Libs/Alert/SRApnsAlert.swift @@ -12,6 +12,8 @@ class SRApnsAlert: SRBaseAlert { private lazy var imageView = UIImageView(image: UIImage(named: "alertBg")) + private lazy var iconimageView = UIImageView(image: UIImage(named: "通知")) + private lazy var titleLabel: UILabel = { let label = UILabel() label.textAlignment = .center @@ -34,22 +36,19 @@ class SRApnsAlert: SRBaseAlert { private lazy var laterButton: UIButton = { let button = UIButton(type: .custom) - button.layer.cornerRadius = 18 - button.layer.masksToBounds = true - button.layer.borderWidth = 1 - button.layer.borderColor = UIColor.white.cgColor - button.setTitle("fableon_open_notification_later".localized, for: .normal) + button.setBackgroundImage(.laterbg ,for: .normal) + button.setTitle("synthreel_open_notification_later".localized, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = .font(ofSize: 14, weight: .semibold) button.addTarget(self, action: #selector(dismiss), for: .touchUpInside) return button }() - override init(frame: CGRect) { + override init(frame: CGRect) { super.init(frame: frame) - highlightButton.setTitle("fableon_open".localized, for: .normal) - - fa_setupLayout() + highlightButton.setTitle("synthreel_allow".localized, for: .normal) + closeButton.isHidden = true + sr_setupLayout() } @MainActor required init?(coder: NSCoder) { @@ -71,35 +70,43 @@ class SRApnsAlert: SRBaseAlert { extension SRApnsAlert { - private func fa_setupLayout() { - containerView.addSubview(imageView) + private func sr_setupLayout() { + contentView.addSubview(imageView) imageView.addSubview(titleLabel) + imageView.addSubview(iconimageView) imageView.addSubview(textLabel) imageView.addSubview(laterButton) imageView.addSubview(highlightButton) + imageView.isUserInteractionEnabled = true imageView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.top.equalToSuperview().offset(-62) + make.edges.equalToSuperview() } titleLabel.snp.makeConstraints { make in make.centerX.equalToSuperview() make.right.lessThanOrEqualToSuperview().offset(-10) - make.top.equalTo(imageView.snp.bottom).offset(10) + make.top.equalTo(10) + make.height.equalTo(18) + } + + iconimageView.snp.makeConstraints { make in + make.top.equalTo(iconimageView.snp.bottom).offset(38) + make.centerX.equalToSuperview() + make.size.equalTo(CGSizeMake(85, 85)) } textLabel.snp.makeConstraints { make in make.centerX.equalToSuperview() make.right.lessThanOrEqualToSuperview().offset(-20) - make.top.equalTo(titleLabel.snp.bottom).offset(12) + make.top.equalTo(iconimageView.snp.bottom).offset(12) } laterButton.snp.makeConstraints { make in make.left.equalToSuperview().offset(23) make.top.equalTo(textLabel.snp.bottom).offset(21) make.bottom.equalToSuperview().offset(-20) - make.height.equalTo(36) + make.height.equalTo(48) } highlightButton.snp.makeConstraints { make in diff --git a/SynthReel/Libs/Alert/SRBaseAlert.swift b/SynthReel/Libs/Alert/SRBaseAlert.swift index 1849294..6ecb219 100644 --- a/SynthReel/Libs/Alert/SRBaseAlert.swift +++ b/SynthReel/Libs/Alert/SRBaseAlert.swift @@ -42,8 +42,6 @@ class SRBaseAlert: UIView { lazy var highlightButton: UIButton = { let button = UIButton(type: .custom) - button.layer.cornerRadius = 16 - button.layer.masksToBounds = true button.setTitleColor(.srGreen, for: .normal) button.setBackgroundImage(.suerButtonBg, for: .normal) button.titleLabel?.font = .font(ofSize: 14, weight: .semibold) diff --git a/SynthReel/Libs/Alert/SRLogoutAlert.swift b/SynthReel/Libs/Alert/SRLogoutAlert.swift new file mode 100644 index 0000000..bda1bc3 --- /dev/null +++ b/SynthReel/Libs/Alert/SRLogoutAlert.swift @@ -0,0 +1,117 @@ +// +// SRLogoutAlert.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/10. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit + +class SRLogoutAlert: SRBaseAlert { + + private lazy var imageView = UIImageView(image: UIImage(named: "alertBg")) + + private lazy var iconimageView = UIImageView(image: UIImage(named: "通知")) + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.font = .font(ofSize: 18, weight: .semibold) + label.textColor = .white + label.text = "logout_alert_title".localized + return label + }() + + private lazy var textLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.font = .font(ofSize: 12, weight: .regular) + label.textColor = .white + label.text = "logout_alert_text".localized + return label + }() + + private lazy var laterButton: UIButton = { + let button = UIButton(type: .custom) + button.setBackgroundImage(.laterbg ,for: .normal) + button.setTitle("synthreel_cancel".localized, for: .normal) + button.setTitleColor(.white, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .semibold) + button.addTarget(self, action: #selector(dismiss), for: .touchUpInside) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + highlightButton.setTitle("synthreel_logout".localized, for: .normal) + closeButton.isHidden = true + sr_setupLayout() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func handleHighlightButton() { + super.handleHighlightButton() + } + + override func dismiss() { + super.dismiss() + adjustManger.manager.apnsFinish() + } + +} + +extension SRLogoutAlert { + + private func sr_setupLayout() { + contentView.addSubview(imageView) + imageView.addSubview(titleLabel) + imageView.addSubview(iconimageView) + imageView.addSubview(textLabel) + imageView.addSubview(laterButton) + imageView.addSubview(highlightButton) + + imageView.isUserInteractionEnabled = true + imageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-10) + make.top.equalTo(10) + make.height.equalTo(18) + } + + iconimageView.snp.makeConstraints { make in + make.top.equalTo(iconimageView.snp.bottom).offset(38) + make.centerX.equalToSuperview() + make.size.equalTo(CGSizeMake(85, 85)) + } + + textLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-20) + make.top.equalTo(iconimageView.snp.bottom).offset(12) + } + + laterButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(23) + make.top.equalTo(textLabel.snp.bottom).offset(21) + make.bottom.equalToSuperview().offset(-20) + make.height.equalTo(48) + } + + highlightButton.snp.makeConstraints { make in + make.width.height.top.equalTo(laterButton) + make.left.equalTo(laterButton.snp.right).offset(11) + make.right.equalToSuperview().offset(-23) + } + } +} + diff --git a/SynthReel/Libs/Alert/SRRemoveCollectAlert.swift b/SynthReel/Libs/Alert/SRRemoveCollectAlert.swift new file mode 100644 index 0000000..3ab894e --- /dev/null +++ b/SynthReel/Libs/Alert/SRRemoveCollectAlert.swift @@ -0,0 +1,117 @@ +// +// SRRemoveCollectAlert.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/10. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit + +class SRRemoveCollectAlert: SRBaseAlert { + + private lazy var imageView = UIImageView(image: UIImage(named: "alertBg")) + + private lazy var iconimageView = UIImageView(image: UIImage(named: "收藏")) + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.font = .font(ofSize: 18, weight: .semibold) + label.textColor = .white + label.text = "remove_collect_alert_title".localized + return label + }() + + private lazy var textLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.font = .font(ofSize: 12, weight: .regular) + label.textColor = .white + label.text = "remove_collect_alert_text".localized + return label + }() + + private lazy var laterButton: UIButton = { + let button = UIButton(type: .custom) + button.setBackgroundImage(.laterbg ,for: .normal) + button.setTitle("synthreel_cancel".localized, for: .normal) + button.setTitleColor(.white, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .semibold) + button.addTarget(self, action: #selector(dismiss), for: .touchUpInside) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + highlightButton.setTitle("synthreel_remove".localized, for: .normal) + highlightButton.setImage(.删除, for: .normal) + closeButton.isHidden = true + sr_setupLayout() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func handleHighlightButton() { + super.handleHighlightButton() + } + + override func dismiss() { + super.dismiss() + adjustManger.manager.apnsFinish() + } + +} + +extension SRRemoveCollectAlert { + + private func sr_setupLayout() { + contentView.addSubview(imageView) + imageView.addSubview(titleLabel) + imageView.addSubview(iconimageView) + imageView.addSubview(textLabel) + imageView.addSubview(laterButton) + imageView.addSubview(highlightButton) + + imageView.isUserInteractionEnabled = true + imageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-10) + make.top.equalTo(10) + make.height.equalTo(18) + } + + iconimageView.snp.makeConstraints { make in + make.top.equalTo(iconimageView.snp.bottom).offset(38) + make.centerX.equalToSuperview() + make.size.equalTo(CGSizeMake(85, 85)) + } + + textLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-20) + make.top.equalTo(iconimageView.snp.bottom).offset(12) + } + + laterButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(23) + make.top.equalTo(textLabel.snp.bottom).offset(21) + make.bottom.equalToSuperview().offset(-20) + make.height.equalTo(48) + } + + highlightButton.snp.makeConstraints { make in + make.width.height.top.equalTo(laterButton) + make.left.equalTo(laterButton.snp.right).offset(11) + make.right.equalToSuperview().offset(-23) + } + } +} diff --git a/SynthReel/Libs/Alert/SRUpdatesAlert.swift b/SynthReel/Libs/Alert/SRUpdatesAlert.swift new file mode 100644 index 0000000..998b835 --- /dev/null +++ b/SynthReel/Libs/Alert/SRUpdatesAlert.swift @@ -0,0 +1,107 @@ +// +// SRUpdatesAlert.swift +// SynthReel +// +// Created by 澜声世纪 on 2025/12/10. +// Copyright © 2025 SR. All rights reserved. +// + +import UIKit + +class SRUpdatesAlert: SRBaseAlert { + + var model: SRVersionUpdateModel? { + didSet { + versionLabel.text = model?.des?.localized + closeButton.isHidden = model?.force ?? false + } + } + private lazy var imageView = UIImageView(image: UIImage(named: "alertBg")) + + private lazy var iconimageView = UIImageView(image: UIImage(named: "升级")) + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.font = .font(ofSize: 18, weight: .semibold) + label.textColor = .white + label.text = "updates_alert_title".localized + return label + }() + + private lazy var versionLabel: UILabel = { + let label = UILabel() + label.textAlignment = .left + label.numberOfLines = 0 + label.font = .font(ofSize: 15, weight: .regular) + label.textColor = .white + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + highlightButton.setTitle("synthreel_update_now".localized, for: .normal) + sr_setupLayout() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func handleHighlightButton() { + super.handleHighlightButton() + guard let url = URL(string: "https://apps.apple.com/app/id6755756350") else { return } + let application = UIApplication.shared + if application.canOpenURL(url) { + application.open(url) + } + } + + override func dismiss() { + super.dismiss() + adjustManger.manager.apnsFinish() + } + +} + +extension SRUpdatesAlert { + + private func sr_setupLayout() { + contentView.addSubview(imageView) + imageView.addSubview(titleLabel) + imageView.addSubview(versionLabel) + imageView.addSubview(iconimageView) + imageView.addSubview(highlightButton) + + imageView.isUserInteractionEnabled = true + imageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-10) + make.top.equalTo(10) + make.height.equalTo(18) + } + + iconimageView.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(38) + make.centerX.equalToSuperview() + make.size.equalTo(CGSizeMake(85, 85)) + } + + versionLabel.snp.makeConstraints { make in + make.top.equalTo(iconimageView.snp.bottom).offset(10) + make.left.right.equalToSuperview().inset(20) + } + + highlightButton.snp.makeConstraints { make in + make.top.equalTo(versionLabel.snp.bottom).offset(15) + make.height.equalTo(48) + make.left.right.equalToSuperview().inset(30) + make.right.equalToSuperview().offset(-23) + } + } +} diff --git a/SynthReel/Libs/Tool/SRTool.swift b/SynthReel/Libs/Tool/SRTool.swift index 36b192a..75a034f 100644 --- a/SynthReel/Libs/Tool/SRTool.swift +++ b/SynthReel/Libs/Tool/SRTool.swift @@ -100,3 +100,56 @@ extension SRTool { } } } + +//MARK: 检查更新 +extension SRTool { + + static weak var updateAlert: UIView? + + static func checkUpdates() { + guard self.self.updateAlert == nil else { return } + Task { + let model = await SRUserApi.requestVersionUpdateData() + guard let model = model else { + adjustManger.manager.upgradeAlertFinish = true + await SRTool.sceneDelegate?.retryHandleOpenAppMessage() + return + } + await MainActor.run { + self.showUpdatesAlert(model) + } + } + } + + static func showUpdatesAlert(_ model: SRVersionUpdateModel) { + guard self.self.updateAlert == nil else { return } +//#if !DEBUG +// if model.force != true { +// if let date = UserDefaults.standard.object(forKey: kFAVersionUpdateAlertDefaultsKey) as? Date { +// if date.fa_isToday { +// FAAdjustStateManager.manager.upgradeAlertFinish = true +// FATool.sceneDelegate?.retryHandleOpenAppMessage() +// return +// } +// } +// UserDefaults.standard.set(Date(), forKey: kFAVersionUpdateAlertDefaultsKey) +// } +//#endif // !DEBUG +// if model.canUpdate() { +// +// Task { +// await SRStatAPI.requestEventStat(orderCode: nil, shortPlayId: nil, videoId: nil, eventKey: .forceUpdate, errorMsg: nil, otherParamenters: [ +// "is_force" : model.force == true ? "true" : "false" +// ]) +// } +// let view = SRUpdatesAlert() +// view.model = model +// view.show() +// self.updateAlert = view +// } else { +// adjustManger.manager.upgradeAlertFinish = true +// SRTool.sceneDelegate?.retryHandleOpenAppMessage() +// } + } + +} diff --git a/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json index 779b252..dbb2ab5 100644 --- a/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json +++ b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json @@ -7,11 +7,33 @@ { "filename" : "recordBottomBg@2x.png", "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "left" : 235, + "right" : 252 + }, + "center" : { + "mode" : "tile", + "width" : 1 + }, + "mode" : "3-part-horizontal" + }, "scale" : "2x" }, { "filename" : "recordBottomBg@3x.png", "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "left" : 230, + "right" : 306 + }, + "center" : { + "mode" : "tile", + "width" : 1 + }, + "mode" : "3-part-horizontal" + }, "scale" : "3x" } ], diff --git a/SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/Contents.json new file mode 100644 index 0000000..84ef7cb --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icon_order@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icon_order@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/icon_order@2x.png b/SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/icon_order@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..96e8c5f63d5e4db7cf3920f5278f0061b3a33391 GIT binary patch literal 691 zcmV;k0!;mhP)O~ z+dvS8|Gi-xJ1=o6K>f@1uyn);nG zaXOW(f*8${KX93o8D-~)$p4D^sEzd#dc92PcZVf~c*NJZ0q zHtrhhF<1n)iW9eo^X6iTAVxjCh9%;Oea;Q1Pwb94q%Ou-^6F-R&l6CEu}xG(i!P{S zQXNY+0uwB)-j||_!lr+1fif*ecmoXHIjulf-n~GpZDus(6JAXKEb)3Yu<36lun-qu zi`WU2ELl!Y38*br0+(M=+oD~?u6(R*Mw8iE9lMfJ5v6DVD}lw=TJUVYTb#+s`m>;n zk2S^Il@xut_=u|R*FhuGtJv*>d0aI%cpchp#+6o}E1Lv**aGo2=XDw?Uwmt;SW>EU zEvxCKJeu&n6e34>B@E%46at2szKY7lTJfl|boRQ0y2qBi9xLmE^4<-wo$NV$i#+r5 Z@BoLi!=Rc$Sj_+c002ovPDHLkV1l&PFg^eP literal 0 HcmV?d00001 diff --git a/SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/icon_order@3x.png b/SynthReel/Source/Assets.xcassets/myShort/icon_order.imageset/icon_order@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..311ea5647a4e5207557eca2221b456ed6a564119 GIT binary patch literal 852 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 e%?BUGepE$oGHYg-o=F1De;3m5Gj{Jl&{Q@b zDoc%9WcrFTf?a{^{Xlf^ZZu&y8ON0DopZW$-CUTHvJ;>M+sHJjdbo`&kiNnUH(!-! zkaB4sO3os#g_XO_VLbUM{h8h&`1lsVx*U_JXPzVAXq3rI({L3*o$)XoOFFTN&AJ?e zn34^q?nUZrNL2t`KAQ6(1Fh@Hv>b;>-|Qi7$w zt4l%uua5Ls1u<)+rrqzuJ^)GPxVFwQ%g^Tr03iLe9SOi0?R!k0)RXNTTAVnzvCmt0iVs7g*fhOxotN57Np6N35z?nZ8Fow`EwH%goT*U zfQ4^By2q0>Q8vQP>n11tKk|1%_v9~I?_%Rim=h5!00i-)6sVc-e+j>*0FU|kaSV;+ z>$rposCEqWK>A})$o<6Mwq8=Q4i}B*G~ReYv3fyM^_-6AB~5q2w9_@F8wf2o;`bh0 zH2$JV?->hjTctpM)AZgmR>06t)t@x(z#N#%gnBe?v01cYZ5rAqWu)U^`HlYM8^cqD-|(mj9#7B?kA% z=gPm!*vNh&%*W{Y!P4*F#CO_o4Bj1Jv*@69=Vlt3nba{5K~kfL>qH}pRWp+xt?XnM zprGYU%utS(TO=@XL(e1aR*weF6U)NhxYejKC|2%(qzbV~lS$HriS`gp}csO~TC+h56akL_rMD>W zU2g>F{smc8MNmlmiWn7C^vf69oC#}QIMg}=qz{!r8rXa>53I1;u~yL40e%6MNgQEe zhgh6u!*J6XWE!Ls`_AKq4+lESboGPZ#;5FsjCM|ua#SiHNX$gCt3mq^^Pmd*9qC=l z>KQMMSs+uyEW``h9muMs&<>ab8j)4Pt0$Y;%mVn=BDM#;mh@2b5UZ@1p`iPFrB6rs z4otXT+0_jRXySn0AY8~9NVNg!!>LV(0;$Br1fQ&8^WlJZfU*irdC3g7h!&=R3uFd_ zp-?3|U=qE&&_9lmIiS`f`wwWU`<-$NIK+7*mIF)}2UaEbLbD1VSHKBG7&67U$PcPe zHx~k9LUIx1SKt*37nKAtf$>66y1H_Nsowe3IBhl>q%%8EZnKA3dW<$Q2Ln&1c#g*2FxZ<0g*i<|o85XC6LqG8 zJyzgO9obHGVAknrix2Zxyh0sbQeRP?Eqy-y?5d+p6AG8oI>KAe-{*wz0l@Y9U0k`` ezv^G%b-{nKbbvyv5x6b@0000-7l literal 0 HcmV?d00001 diff --git a/SynthReel/Source/Assets.xcassets/normal/弹窗按钮背景.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/normal/弹窗按钮背景.imageset/Contents.json index 4a269be..9b354e6 100644 --- a/SynthReel/Source/Assets.xcassets/normal/弹窗按钮背景.imageset/Contents.json +++ b/SynthReel/Source/Assets.xcassets/normal/弹窗按钮背景.imageset/Contents.json @@ -7,11 +7,33 @@ { "filename" : "弹窗按钮背景@2x.png", "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "left" : 94, + "right" : 92 + }, + "center" : { + "mode" : "tile", + "width" : 1 + }, + "mode" : "3-part-horizontal" + }, "scale" : "2x" }, { "filename" : "弹窗按钮背景@3x.png", "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "left" : 136, + "right" : 141 + }, + "center" : { + "mode" : "tile", + "width" : 1 + }, + "mode" : "3-part-horizontal" + }, "scale" : "3x" } ], diff --git a/SynthReel/Source/Assets.xcassets/normal/收藏.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/normal/收藏.imageset/Contents.json new file mode 100644 index 0000000..2fcc7b2 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/normal/收藏.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "收藏@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "收藏@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SynthReel/Source/Assets.xcassets/normal/收藏.imageset/收藏@2x.png b/SynthReel/Source/Assets.xcassets/normal/收藏.imageset/收藏@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7f8a87f58d26bb95e4ce4ef6a8cd2e1a4ad56c0c GIT binary patch literal 19801 zcmV*9Kybf_P)zv7M0wRmLVI(MD4?N$~|V&;Yvo zKF-S8dp-8rryC#}FE)g`f!p`qbI)U+eZKvzZ>_b@J^+(4DU&iOlQJojGAWZXDU&iO zlQJojGAWZXDU&iOlQJoja@7}vNxA59fR4?N+LZ@@U_T=6Yk`&;#3e*H+yFdv1mCp? zlX6jI0@RBv_l=)IIYoD^D+sr|=lFCS?Lm1&vaR)yJd)GGLP$kY)Wo?44-V&6f$IUO*X7 zHHl3VBr)mI%%UVvO{mRGN(xRAu=1K2s^c+CSoH$Rgi$wH5}S^u@Xr%4vl3+h3KE@L zGdNM;3gTVW4ptxFo+DH5dJ-n(4VMX{Zn7jcMTev?sd`MPtm@{UGJ0h_Sxwk?3^-xc zO_m9xZlbUQwV(O(iK^9%CQ*PXpOG@FMn=u(Mg5o-(>-6Bu<9Ew6Gq)cL1n^(J<*@y zK~V;#@ueVA(I}v`r6e0<7mOyXx|uQo>KiQg4xT>90NXFrX+bD*V5Yxf=}i@+MNN(h zWFe5ls|MQqXMbX7n3OkECP00og;<+ha4anSomi{tLX3dJ|TC zgJlBLH&E^!eET5dY=Md*4KlTarkqjJ-yG;K$Q4MV=vXqa)BbzczI6a5<#o#hsBfeY zW#&Tzq(d-zRj9vfNTBFZ*@dlziHwt8O-dlI`D-vKuUjTSeVrm~ihGLDM^&hrmr^8B z;7vlmYHLBHC_6E7A+m3Ktt zPPXbKSu1|Et%U(VC>GZ>`%-Uuic_n5mtayhEE7gOPq}yH+XoX!J?In>W?qu#_toH= zV}(r)@>5P;IpZ>X8-h3nP-MjQqt(IRgGo7OnK0@(%7K+*3u7EU!5FtDdh+81)=w)Qlcr^ax1FbE1J!#aTl84b1BMFhAeSbN_i8 zDw`B0PTS6p2BV2qJx7@^>IOyFbo34WIG?`TsQs940xH4NqC0gI09l$;#{k67n#Ce& z5p^3Gvy%6*)SKx~SapLkVbl%ExEVjhZ}XY?$TLsXAQLMxYN{bmk+ub!VepDCEZWwD ztKy#b!Jn>gS0}8xQJFAmr(`yT(Xo90ldxPzR~Fx1S+dft8|qIhvM*exW23fh@Ih)U|N`+=(##XeaN(5)v5~3=@tIOwd6QFI=!`|Kr ztClih)KD^$q2}(*4^s9tSQU>w8*)umX|{?8H?r&{l;s|N{INs;B(#89m&agIyi6EX zOJUOuVxb!>%Vs;@ixM;`YI4=q)zDTYAWZv)-(~j{G_LHY#rB>r&Hdn$Fewv8wIU3L zo$*onYKv14Uk8_f-5+Jl2bI#V$Y={?oqvbbDJzAg(b3@7PLhrpgBQ?=d^MQ4qsbMSz1Af zwrSqC1G@~w24`}BefO;#djPKCa&0qeVpIE=gY{H~oq*sm$MP-vRE#=B2TI77I{Pl$ ztM;Ti3#EU3WR-dR7~L)%36tsu55qNFu34ZaHf0zrbTuQyaK7F)l0ilUW#&E^u2(zi z#=j7pEM-+&-_3b}q3zq`0qC6px*r*NEt+A^eP@n61lMRmxJJvpr~mvI18box8qHv< znOA2@eg){>L=t~4OZ=k`RakaWj_sDsrL^XS^dDu;PazW(YVyvzmdd)FvJAwz3Hq}W>DS%ONXhZJ=C^q0Ef>g6ox%dsy63q7j|GJtaM@_$C zam);?XdQ)QbPJGYv3&kjSP8sC5ME3>b3$WKJ3B=DD)XgZC|8TaMK=WBM7S zzsA@4L4Y!&nP)k{ri4u8Joh_=QcW=lQ)Qbh2aUG2pRQu^V zatW{S@E5o5c?7P3@_h}|tVc)91AN^N@}*uV^OF`$XnN3QGO_vgO=t>2T*s=ubhGYr zpr%4GmQ{|M?J%ejITITbXz~Co#+y46gB6eQ8c#LUd=qwzj($Jf)p}I{^}vZ^ z^P@iOYp}UH4J2Vu?&k}VnDY7zA-izKQVOJw8PBB#13>v&maYqOhJDLE3$cZrkk!TQ zHLaHq#VZp6ub36%9jxHz1nCy*4eAEnI=briN3|^RvZIL2QEKVAUeg@C+5o&Iftmmb zQ&S7$cF4@w+}*I3E-VQP>36^AiWVV~g2%k94Pl~lo+TEE3dPNV#tF-!0zs>a@y*oM zh#t**a^$1VI~5PZ%Pc*s+f-)W>kgs2)Q|lU&wu@QtCw{n2p|CYtc|wCa4ZFGW_3iWjv3^H)mx5M&f7z0Ax>Lq;2=Yw zoUR|k4q%QVRdNF=#*gR2@65iq$Orl+Z*i0vc=5=Nx4)_S_lf~E19Hd=Nwm-)-km0~ z<;4r@j4MKsUlh$)tZr@i)YjS;ry2_xAw)1^SJMTvjP7Gm*~nPPgYWV+R@9dI>J?Ml zx?odT_&5Qow~P*4*alI+iQQwH18DbU`Se2s7Ulw@*wTq0=K-zEjTURGgmQaCr7jE^!$B^S2@Zb7L$x@IO{+@vt#Rm@5H#}GIh&#>{bRT#**i^roQ^uc!l&|~ z@l>V)E}TqEd6LQypG*Z@2DnKs7zp(R4E2D{XRk}>61DcUIPn+z#|?d!Yq}RIvb5HKq8U3S zc;@Ab#r$@82OT*Ct%_AF`E|5yttXVmulGw~Y91fZA45n`F&IERMyYlEu{!7a=hzO_ zPU5%#tH13A?IIUb4>m$JBm{In3Z&2%p?*WC{`h{p{k{G4xTfvnx#_xESto}oS>baa zY(VwW{)_AoA3CyY_mgme<${5F|Ea%xVBEHcD;CkSlXD4q@v0X>Ty8|ER|7*_2jYb& z_s56eyRRTI?SKt=9Q>lUlbS1s87E>pGh1y!+~`SF?&PSKS3gj`~#PzKygY zcJ}TjoIGaPsS*|$Q|biOI(C)o4cDKW9j_c00H`>6^*+hXxa>0BwRDOhUISH zVq!5rd#O-vNMxIK1hab8{>&hU{i=1=t81*KJ~fumr|ty-yLlio#8t;pB&Yi76y`pt z1nq1v)=TuajyVPUu5D6~Ls0m-v`pda!fGUanbV?ru68?&j=}Qd3!$ksj!9Z72Sul2 zs}Dk<;0V_4Cu30Ax64r7M+4H%7~=$;UWtB|ex33JaHGfI0?MWtHM1!gn|AjWgu8Yr z_Yh-fB&2KBeJ(LVh;d1^L#5aHwh*L8I4kW8uz^0_xV}LX2a^X-F@?uO8>n;o)p0w8 zy7A7=`Wvcw5_R}t6j@l3zPjHw+pbz zvU!c#l%qN;wBWi;$WnVS6kVeiSsJJdpjA!unTjO-l}t*yua8TqOL zumKza%z>nEdRF&TfjozSuR;(ywe2@*?gBckTL3cTCZ;MHi{ZN2cCEs~&$n$OW4xi# zhfSB>3A-NNI^7hVoPp7Zo>+|E+2D$h>#XC8+90I2cNEK6)^JUyPBIB$bwC`07(4Q&$g^9K`t zE+1k$+xK;0E3D|#Drf7Xl0&z2^*$97W<86#Ru2I>5+&_<(^;!cGin3)c!m)LcVEq( zo1Q2Mq$x{J)XGLk$X_a&i?lJR^hnoldAZ^P*V(yPvJ?uV1Xk53M-0JQnXX-x%vTX zeO6!Octmc5){sc+0EiW6Y@vm*46woB?(}#9?^-@&FEB2aJv-~Ht+W(@>cK z$*cl-n;~@Cfa(*M-}837Q3EAXjG?pC#Ah*BAZ0t>m);rZEFU{V?3^~4TWN(-Pi<4m z@}bny8qz;jeu(W`pIFHMpS)smRK)(riY~$8Ef=kd+JCTUo6wW>ia{`0p;1*+mPg`v z6T6uXY#lw#wty#sLm?aVZPA-~*Dav!AA^G+@3s$8E(=$&a0S$!6&5gBptJm97nD0- z+2QJQ1*hke* zu%qK6i!0Oiuy+V9pj;48kLzuAYW??z`AUKSd48gKg5fm0~(G;yL0;<M3#06Om8~1 zRheV9p@g}}w5G9K1e|^M^Edr$`vkW{-o|LBA&dwP^45Hi0DP+U;Vf^R+?`XCXlPaq zKXxH(n#u*=E`4Oz+aG1`?U7h<2blNDVqRo5f?`TE1QfRefEdoQZOrrv9Q1cLEri9b z)BKG=vxH$>3Y5A)RSyS`4UCE3txo>gM|(kFck=CgeRb|a=c~TUcGf};n!=ocS!3I| z{_|s7dnrsyOw+SM3iGH>J*8ZTqEM}MQYhxz1&g(rg$(n<++5l~X=^BP@bUPOe|h8E z9)$}m2p3rny!QOVT$hKO9n^wAWzDgZA*z421-4r~koua8xI-8!-l9hT_cx9{7`j`qjQ-b#s~D+0!KJB_6uT>-#3 z+PFG<`9cJND(naAiWnM%x^3d}Aa_l4)+URZVDrcqZ@l$kxQKGmKuzVoSDt^EEBKIG z$@&l_92Fs8nIkB}#ccZV8Y19LS(ad(t_!P|SSsN<(0ASgVyVQPYKjwrE$cz;&lSwY z^CBJd67H!gm6Z0-he-r$WI#eS0Dyj;Sb!|3E!w?0$4+}})Y7}bEa*#tryx0ojYUW1Wg=?*nuGQ=pzk7BRf;4{WJi@$w8&H!dBrp z-vxz16>~awwsl1B|;lUr4UhBSK6v4ES$@MYM2}Ui5ssmP1vo{I>7J{LXFOR_;dN&% zrn{^|V5}YjlD1KUWiUjlYhz;|Ajk==Px{-E-XjgQiSY~JCkNi))^!N^Q~an%N{Au^;`EBhXF}`6)o?eH40aJ>){D%bAwazT>TZZQak2lD<6LKrN{Ve z4sNXRq{*B-yoZJhV7zM=$Gz^fO5-lXFBrr&?cAIPa=y)WKGpAKFoSkhVjrPl_rusIf2~VbiH!s86}u z0-{z>U!$oU!wx}%W`#fT#hc!C*=EDOtUygAgOv=dWDF6ITFkDY3u?uLyzDi z*lXUvA_MibId-gW{W|MF70Quc41+O}5I_xDJ&!D5=`~=klztZ-Tl7NId$ymT5u=W& zPZK-!bg-fXQLDDW(yrCo@<|~Z>R`u^8xISMLcLD$KZri}#anJY2$!*3cA%zm@5?Ve z)}*N)A@ss<)w|vYh1jcUH{V8U9RZ4+W~3_42dZ1;19gr`Ay!$_2^8nS;=3w1h`M?% zhJ~Q^1QoS5=TvpB1}`(A1ri?KwfaSmD;?dU6Tbh@K_RT`1VAB5LdMvg9;a;`F&&r} zU5a?PENAX6J4me_SEStc@=J&LWFK%36#!xwM;68w!VP1W!oa!FHEpAznizM~<<-4N zZsrMMOjDp&OmLY4b%Qu0QB|)p1&^Oetel(sTaxM*dqyYfS#369x@tfar zKU|@5Md$EurlynFK3cqNX&AfS*|{bVLeop@y;*!;-&by28=lwdsfg#Ett04giM*va z4;b>~-~%-X3M<<6i~o#Fawo818t7&)S50nh)_sd}zHWrP3~)hBJt!lFx@l0v`kCRJ zO5mO-Wag@Nuv+DFrlJM_J1tfW7^t^j^*05%btDK8iq5$l#nWdG!4)i5lu=VTaN@)~ z4F^x~mDpF}RE&uR832VlLBEw-fGb;wMf(C&=B%XqC0rDeD|tN(IyX#Y zQA}+Z&jIU#dpcC2dV8(pKe7JcW%kwk(Ibpm#_y8f)Edk zIuBf`S$x&uZ$JWoszZ>`D?kKk=m=hneykT%U7=`E!)=j_Rav*+jF+GjZT>7U(3uXc zNi~%j{`$6FA9iw}^rofM|SOmu41@7Xi@Ei!SgobOi)0q`~3lC&38{v(@hQH8D8NuuXSqN zx&$F#)9d0&LNI3iiNKyAkPpfLZ^vVV(FnG;W0>b(uIIWR*_Xn+7!cXLO)^wnhGWDWfvU=R+dYxE*?h;$nfKb$3i40*UI#0ES z23k!ja}HF8jG8)V21_FFHik?AaT*aew3KfcMNs3TLm~{XX{yEzsjHPxp&7e_!Q>l7zv>7 zo}PjP(39;LUmmwGBpV|l(T7&ICs4jq;8T&`p3y5263Ce~Irlbc1Q3vpfJP&twKZg* zQhRm<+m*A>o;?e=x&phJ2Ht+%b;ov0O?~Qb-E+^cz?)pQ3{X=!@Zt#u>(IeU9han- z?FcX|HZQVm@dQk>om2a+|80ZP(Gr#8WVP#hP+C7~{f=kcXpeXH`|zW)Gwj?Dy)+u* zC=nmHX;+BZJaa{pQ|E{j_ghs(=JBBn(s2SQa)=PvKY*5*v|U@t0Bz5nfpLCcVc?!& zA$%5Y*}ffi-+1HV+|<;=5B!b4@i};t%9a9ZD#EN&PjEZ$Dd8ljwy4-}qh~YjSGDywjuTi_Yg5#C5)Sfr!^8c<;kuX47_UK1Qf$#rXHfpB-6G#`R~ten*;W- zfwgEh=^2brO#T>(7hlN$J$CEIE<_#cUD+BLIFWT}%OIseda)*5U4v0_oEVg&)2A~) z8LSN2WdZCN)~D%rW>aAH#nF%%wFQ}G0;tCgxUgpryz|bxj&e-*{zHcjEy86kTN
hMr7 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%0AA~wWU*CZuLMu-QDKK4TS-}2% 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 JPi8(z{{t`(8QK5< literal 0 HcmV?d00001 diff --git a/SynthReel/Source/Info.plist b/SynthReel/Source/Info.plist index 8bacbe1..97a8b46 100644 --- a/SynthReel/Source/Info.plist +++ b/SynthReel/Source/Info.plist @@ -25,6 +25,8 @@ 1203129771732470 NSUserTrackingUsageDescription We will use your advertising identifier (IDFA) to provide a personalized advertising experience. + GADApplicationIdentifier + ca-app-pub-6275401933109862~8769451155 FacebookClientToken 3e671125d76ef8555893cd453337ccfc UIApplicationSceneManifest diff --git a/SynthReel/Source/en.lproj/Localizable.strings b/SynthReel/Source/en.lproj/Localizable.strings index 22dbb52..0994a3f 100644 --- a/SynthReel/Source/en.lproj/Localizable.strings +++ b/SynthReel/Source/en.lproj/Localizable.strings @@ -28,6 +28,7 @@ "synthreel_user_agreement" = "User Agreement"; "synthreel_delet_account" = "Delet Account"; "synthreel_visit_website" = "visit website"; +"synthreel_order_Record" = "Order Record"; "Viral Hits" = "Viral Hits"; "Live Trending Rankings" = "Live Trending Rankings"; "empty_title_01" = "No search results"; @@ -102,7 +103,19 @@ "pay_error_6" = "You have unfinished in-app purchases, please restore them first."; "synthreel_open_notification_later" = "later"; +"synthreel_allow" = "Allow"; "coins_pack_alert_title" = "Daily Reward is waiting!"; "synthreel_claim_now" = "Claim Now"; "synthreel_daily_coins" = "Daily Coins"; "apns_alert_title" = "Don’t miss updates!"; +"apns_alert_text" = "Get new episode alerts & rewards."; +"updates_alert_title" = "Discover a new version"; +"synthreel_update_now" = "Upgrade now"; +"logout_alert_title" = "Leaving so soon?"; +"logout_alert_text" = "Your progress will be saved."; +"synthreel_logout" = "Log out"; +"synthreel_cancel" = "Cancel"; +"remove_collect_alert_title" = "Remove from your list?"; +"remove_collect_alert_text" = "This drama will be removed from your saved list."; +"synthreel_remove" = "Remove"; +"synthreel_my_wallet" = "My Wallet"; diff --git a/SynthReel/SynthReel.entitlements b/SynthReel/SynthReel.entitlements index 80b5221..fe942f6 100644 --- a/SynthReel/SynthReel.entitlements +++ b/SynthReel/SynthReel.entitlements @@ -8,5 +8,9 @@ Default + com.apple.developer.associated-domains + + applinks:synthreel.go.link + diff --git a/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/build-request.json b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/build-request.json new file mode 100644 index 0000000..38eab09 --- /dev/null +++ b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/build-request.json @@ -0,0 +1,27 @@ +{ + "buildCommand" : { + "command" : "build", + "skipDependencies" : false, + "style" : "buildOnly" + }, + "configuredTargets" : [ + + ], + "continueBuildingAfterErrors" : false, + "dependencyScope" : "workspace", + "enableIndexBuildArena" : false, + "hideShellScriptEnvironment" : false, + "parameters" : { + "action" : "build", + "overrides" : { + + } + }, + "qos" : "utility", + "schemeCommand" : "launch", + "showNonLoggedProgress" : true, + "useDryRun" : false, + "useImplicitDependencies" : false, + "useLegacyBuildLocations" : false, + "useParallelTargets" : true +} \ No newline at end of file diff --git a/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/description.msgpack b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/description.msgpack new file mode 100644 index 0000000000000000000000000000000000000000..c43eb886672622af27c38f8d7d161de1b649c216 GIT binary patch literal 253 zcmW-bK~BRk6ht`#C+G?M9pfbSmUN4RsF2uIw*OBW>e^MDhPJC5A>4qoKrc~=!;mtY zk=`uc{NCMPOL$GxCGaV|!;;drk9%01Lce(-^6(rn0b^hftw(sP9&f!gy}2w1g_KCO zHMT(E1TP*6n+xO0f-EQe{2Iq`8m}G((?K0Q-aMHHtxtXaQRcb!^?AKNuFpE#4odPl zO@Inw*D&vg9dq7<2A(1wJXOYRh=te&q$8{-r8Wk(``-rRTQvO)#_6&^nW1v1Rn55- UT#{CtYpuxDN{W)E`PKK&AHD)wJOBUy literal 0 HcmV?d00001 diff --git a/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/manifest.json b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/manifest.json new file mode 100644 index 0000000..7391713 --- /dev/null +++ b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/manifest.json @@ -0,0 +1 @@ +{"client":{"name":"basic","version":0,"file-system":"device-agnostic","perform-ownership-analysis":"no"},"targets":{"":[""]},"commands":{"":{"tool":"phony","inputs":[""],"outputs":[""]},"P0:::Gate WorkspaceHeaderMapVFSFilesWritten":{"tool":"phony","inputs":[],"outputs":[""]}}} \ No newline at end of file diff --git a/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/target-graph.txt b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/target-graph.txt new file mode 100644 index 0000000..b83b158 --- /dev/null +++ b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/target-graph.txt @@ -0,0 +1 @@ +Target dependency graph (0 target) \ No newline at end of file diff --git a/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/task-store.msgpack b/build/XCBuildData/ed244defbab6d2c20636b52ac76eb0ed.xcbuilddata/task-store.msgpack new file mode 100644 index 0000000000000000000000000000000000000000..6cef3fe35dc37f3eb3b88d5dc171a6a7189718d4 GIT binary patch literal 79 zcmbPuhe6^15KLO)o>-E4Q!zZhD7&~IF*(&EH8CZ%$TzVd%q`e0Gbgn;yePAzBsFir egb9--OjxLY_`rd~hbA1JFyX+V%M4I(=nw#{5hHQ{ literal 0 HcmV?d00001