web view
1
Podfile
@ -32,4 +32,5 @@ target 'SynthReel' do
|
||||
pod 'collection-view-layouts/TagsLayout'
|
||||
pod 'HWPanModal'
|
||||
pod 'LYEmptyView'
|
||||
pod 'ZLPhotoBrowser'
|
||||
end
|
||||
|
||||
@ -125,6 +125,21 @@
|
||||
3754ACBF2ED5B839009EBCAD /* SRNavgationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACBE2ED5B839009EBCAD /* SRNavgationTitleView.swift */; };
|
||||
3754ACC12ED69105009EBCAD /* SRTopChartsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACC02ED69105009EBCAD /* SRTopChartsHeaderView.swift */; };
|
||||
3754ACC42ED6EDA6009EBCAD /* SREmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACC32ED6EDA6009EBCAD /* SREmpty.swift */; };
|
||||
3754ACD12ED81F55009EBCAD /* SRBaseAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACD02ED81F55009EBCAD /* SRBaseAlert.swift */; };
|
||||
3754ACD32ED82113009EBCAD /* SRGradientbutton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACD22ED82113009EBCAD /* SRGradientbutton.swift */; };
|
||||
3754ACD52ED82722009EBCAD /* SRDetailRecommendview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */; };
|
||||
3754ACD72ED82774009EBCAD /* SRDetailRecommendCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */; };
|
||||
3754ACDA2ED8374D009EBCAD /* SRPagerViewTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACD92ED8374D009EBCAD /* SRPagerViewTransformer.swift */; };
|
||||
3754ACDC2ED83F80009EBCAD /* SRHomeHistoryBottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACDB2ED83F80009EBCAD /* SRHomeHistoryBottomView.swift */; };
|
||||
3754ACE12ED93C4D009EBCAD /* SRCoinPackController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACE02ED93C4D009EBCAD /* SRCoinPackController.swift */; };
|
||||
3754ACE42ED93E3B009EBCAD /* SRBaseWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACE32ED93E3B009EBCAD /* SRBaseWebViewController.swift */; };
|
||||
3754ACE62ED93E7C009EBCAD /* SRWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACE52ED93E7C009EBCAD /* SRWebView.swift */; };
|
||||
3754ACE82ED93ED9009EBCAD /* SRWebMessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACE72ED93ED9009EBCAD /* SRWebMessageModel.swift */; };
|
||||
3754ACEA2ED94065009EBCAD /* SRBaseWebViewController + Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACE92ED94065009EBCAD /* SRBaseWebViewController + Script.swift */; };
|
||||
3754ACEC2ED943AB009EBCAD /* SRAppWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACEB2ED943AB009EBCAD /* SRAppWebViewController.swift */; };
|
||||
3754ACEE2ED945A1009EBCAD /* Dictionary+SRAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACED2ED945A1009EBCAD /* Dictionary+SRAdd.swift */; };
|
||||
3754ACF02ED94A4C009EBCAD /* SRFeedBackController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */; };
|
||||
3754ACF22ED975B9009EBCAD /* SRRewardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3754ACF12ED975B9009EBCAD /* SRRewardController.swift */; };
|
||||
3779D0612ECF1CB8006B1698 /* SRShortHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */; };
|
||||
47BB39E2DD30787FA591F8EB /* Pods_SynthReel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9255BF4D4B1CFDDB5CFFB43 /* Pods_SynthReel.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -249,6 +264,21 @@
|
||||
3754ACBE2ED5B839009EBCAD /* SRNavgationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRNavgationTitleView.swift; sourceTree = "<group>"; };
|
||||
3754ACC02ED69105009EBCAD /* SRTopChartsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRTopChartsHeaderView.swift; sourceTree = "<group>"; };
|
||||
3754ACC32ED6EDA6009EBCAD /* SREmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SREmpty.swift; sourceTree = "<group>"; };
|
||||
3754ACD02ED81F55009EBCAD /* SRBaseAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRBaseAlert.swift; sourceTree = "<group>"; };
|
||||
3754ACD22ED82113009EBCAD /* SRGradientbutton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRGradientbutton.swift; sourceTree = "<group>"; };
|
||||
3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRDetailRecommendview.swift; sourceTree = "<group>"; };
|
||||
3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRDetailRecommendCell.swift; sourceTree = "<group>"; };
|
||||
3754ACD92ED8374D009EBCAD /* SRPagerViewTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPagerViewTransformer.swift; sourceTree = "<group>"; };
|
||||
3754ACDB2ED83F80009EBCAD /* SRHomeHistoryBottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRHomeHistoryBottomView.swift; sourceTree = "<group>"; };
|
||||
3754ACE02ED93C4D009EBCAD /* SRCoinPackController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackController.swift; sourceTree = "<group>"; };
|
||||
3754ACE32ED93E3B009EBCAD /* SRBaseWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRBaseWebViewController.swift; sourceTree = "<group>"; };
|
||||
3754ACE52ED93E7C009EBCAD /* SRWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRWebView.swift; sourceTree = "<group>"; };
|
||||
3754ACE72ED93ED9009EBCAD /* SRWebMessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRWebMessageModel.swift; sourceTree = "<group>"; };
|
||||
3754ACE92ED94065009EBCAD /* SRBaseWebViewController + Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRBaseWebViewController + Script.swift"; sourceTree = "<group>"; };
|
||||
3754ACEB2ED943AB009EBCAD /* SRAppWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRAppWebViewController.swift; sourceTree = "<group>"; };
|
||||
3754ACED2ED945A1009EBCAD /* Dictionary+SRAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+SRAdd.swift"; sourceTree = "<group>"; };
|
||||
3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRFeedBackController.swift; sourceTree = "<group>"; };
|
||||
3754ACF12ED975B9009EBCAD /* SRRewardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRRewardController.swift; sourceTree = "<group>"; };
|
||||
3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRShortHeaderView.swift; sourceTree = "<group>"; };
|
||||
59DC746604B26E9FF802D317 /* Pods-SynthReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.debug.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
AA88214030574193B51DE563 /* Pods-SynthReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.release.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.release.xcconfig"; sourceTree = "<group>"; };
|
||||
@ -354,6 +384,7 @@
|
||||
03B1A8F82EC813BC006C353F /* SRScrollView.swift */,
|
||||
03B1A8FE2EC81C92006C353F /* SRImageView.swift */,
|
||||
03B1A9062EC86656006C353F /* SRGradientView.swift */,
|
||||
3754ACD22ED82113009EBCAD /* SRGradientbutton.swift */,
|
||||
03B1A93D2ECC4568006C353F /* SRTableView.swift */,
|
||||
03B1A93F2ECC45BA006C353F /* SRTableViewCell.swift */,
|
||||
03B1A94B2ECC7A2D006C353F /* SRPanModalContentView.swift */,
|
||||
@ -394,6 +425,7 @@
|
||||
370D2F2A2ED597F700571E77 /* SRTopChartsCell.swift */,
|
||||
370D2F2C2ED5AA9700571E77 /* SRViralHitCell.swift */,
|
||||
3754ACC02ED69105009EBCAD /* SRTopChartsHeaderView.swift */,
|
||||
3754ACDB2ED83F80009EBCAD /* SRHomeHistoryBottomView.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -465,6 +497,8 @@
|
||||
03B1A9472ECC6669006C353F /* SRProgressView.swift */,
|
||||
03B1A9492ECC79AB006C353F /* SREpSelectorView.swift */,
|
||||
03B1A94D2ECD604B006C353F /* SREpSelectorCell.swift */,
|
||||
3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */,
|
||||
3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -525,6 +559,7 @@
|
||||
03E9A7D22EC47204000D1067 /* Base */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACE22ED93E04009EBCAD /* webview */,
|
||||
03B1A8412EC5CB4F006C353F /* ViewController */,
|
||||
03B1A8D62EC6D03A006C353F /* View */,
|
||||
03E9A7F02EC4A8DD000D1067 /* Extension */,
|
||||
@ -538,6 +573,7 @@
|
||||
03E9A7D32EC4720F000D1067 /* Class */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACDD2ED93C14009EBCAD /* Coinpack */,
|
||||
370D2F0D2ED4532100571E77 /* User */,
|
||||
03980F542ECEEC990006E317 /* MyShort */,
|
||||
03B1A84E2EC5DB13006C353F /* Home */,
|
||||
@ -549,6 +585,8 @@
|
||||
03E9A7D42EC4764A000D1067 /* Libs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACD82ED83724009EBCAD /* FSPagerView */,
|
||||
3754ACCF2ED81F2F009EBCAD /* Alert */,
|
||||
3754ACC22ED6ED92009EBCAD /* Empty */,
|
||||
03B1A83C2EC5C90F006C353F /* Tool */,
|
||||
03B1A8372EC5C8BF006C353F /* SRHud */,
|
||||
@ -611,6 +649,7 @@
|
||||
03B1A91A2ECAFFCB006C353F /* UIView+SRAdd.swift */,
|
||||
03B1A91C2ECB241B006C353F /* UIScrollView+SRAdd.swift */,
|
||||
3754ACBC2ED5B6B6009EBCAD /* UINavigationBar+SRAdd.swift */,
|
||||
3754ACED2ED945A1009EBCAD /* Dictionary+SRAdd.swift */,
|
||||
);
|
||||
path = Extension;
|
||||
sourceTree = "<group>";
|
||||
@ -650,6 +689,8 @@
|
||||
370D2F1D2ED54C7F00571E77 /* SRHelpCenterController.swift */,
|
||||
370D2F1F2ED54C8F00571E77 /* SRAboutUsController.swift */,
|
||||
370D2F212ED54CA400571E77 /* SRPrivacyController.swift */,
|
||||
3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */,
|
||||
3754ACF12ED975B9009EBCAD /* SRRewardController.swift */,
|
||||
);
|
||||
path = VC;
|
||||
sourceTree = "<group>";
|
||||
@ -682,6 +723,58 @@
|
||||
path = Empty;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754ACCF2ED81F2F009EBCAD /* Alert */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACD02ED81F55009EBCAD /* SRBaseAlert.swift */,
|
||||
);
|
||||
path = Alert;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754ACD82ED83724009EBCAD /* FSPagerView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACD92ED8374D009EBCAD /* SRPagerViewTransformer.swift */,
|
||||
);
|
||||
path = FSPagerView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754ACDD2ED93C14009EBCAD /* Coinpack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACDF2ED93C36009EBCAD /* view */,
|
||||
3754ACDE2ED93C2A009EBCAD /* VC */,
|
||||
);
|
||||
path = Coinpack;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754ACDE2ED93C2A009EBCAD /* VC */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACE02ED93C4D009EBCAD /* SRCoinPackController.swift */,
|
||||
);
|
||||
path = VC;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754ACDF2ED93C36009EBCAD /* view */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = view;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3754ACE22ED93E04009EBCAD /* webview */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3754ACEB2ED943AB009EBCAD /* SRAppWebViewController.swift */,
|
||||
3754ACE32ED93E3B009EBCAD /* SRBaseWebViewController.swift */,
|
||||
3754ACE92ED94065009EBCAD /* SRBaseWebViewController + Script.swift */,
|
||||
3754ACE52ED93E7C009EBCAD /* SRWebView.swift */,
|
||||
3754ACE72ED93ED9009EBCAD /* SRWebMessageModel.swift */,
|
||||
);
|
||||
path = webview;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3779D05F2ECF1C8D006B1698 /* V */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -836,8 +929,10 @@
|
||||
03B1A9402ECC45BA006C353F /* SRTableViewCell.swift in Sources */,
|
||||
03E9A7EA2EC4995D000D1067 /* SRKeychain.swift in Sources */,
|
||||
03E9A7D92EC47B90000D1067 /* SRNetworkReachableManager.swift in Sources */,
|
||||
3754ACD72ED82774009EBCAD /* SRDetailRecommendCell.swift in Sources */,
|
||||
370D2F2D2ED5AA9700571E77 /* SRViralHitCell.swift in Sources */,
|
||||
03B1A8532EC5E12E006C353F /* UIScreen+SRAdd.swift in Sources */,
|
||||
3754ACF02ED94A4C009EBCAD /* SRFeedBackController.swift in Sources */,
|
||||
370D2F182ED45B3000571E77 /* SRUserSettingModel.swift in Sources */,
|
||||
03B1A8FB2EC818BE006C353F /* UIStackView+SRAdd.swift in Sources */,
|
||||
03B1A8E12EC6D6D3006C353F /* SRHomeMenuDataSource.swift in Sources */,
|
||||
@ -854,12 +949,17 @@
|
||||
03E9A7DB2EC485BE000D1067 /* SRNetwork.swift in Sources */,
|
||||
370D2F152ED457F000571E77 /* SRUserTopCell.swift in Sources */,
|
||||
3754ACBD2ED5B6B6009EBCAD /* UINavigationBar+SRAdd.swift in Sources */,
|
||||
3754ACE82ED93ED9009EBCAD /* SRWebMessageModel.swift in Sources */,
|
||||
03E9A7F42EC4A94D000D1067 /* SRAccountToken.swift in Sources */,
|
||||
3754ACD12ED81F55009EBCAD /* SRBaseAlert.swift in Sources */,
|
||||
370D2F222ED54CA400571E77 /* SRPrivacyController.swift in Sources */,
|
||||
370D2EF72ED000C400571E77 /* SRFavoritesViewController.swift in Sources */,
|
||||
370D2F072ED3FEFA00571E77 /* SRFavoritesCell.swift in Sources */,
|
||||
3754ACE42ED93E3B009EBCAD /* SRBaseWebViewController.swift in Sources */,
|
||||
03B1A8E72EC7175D006C353F /* SRCategoryModel.swift in Sources */,
|
||||
370D2F2F2ED5AB2500571E77 /* SRViralHitController.swift in Sources */,
|
||||
3754ACDA2ED8374D009EBCAD /* SRPagerViewTransformer.swift in Sources */,
|
||||
3754ACF22ED975B9009EBCAD /* SRRewardController.swift in Sources */,
|
||||
03B1A94A2ECC79AB006C353F /* SREpSelectorView.swift in Sources */,
|
||||
03B1A94E2ECD604B006C353F /* SREpSelectorCell.swift in Sources */,
|
||||
03B1A9262ECBFF31006C353F /* SRShortPlayerViewModel.swift in Sources */,
|
||||
@ -869,6 +969,8 @@
|
||||
03B1A9482ECC6669006C353F /* SRProgressView.swift in Sources */,
|
||||
370D2F1A2ED45CCA00571E77 /* SRUserSettingCell.swift in Sources */,
|
||||
03B1A91D2ECB2424006C353F /* UIScrollView+SRAdd.swift in Sources */,
|
||||
3754ACE62ED93E7C009EBCAD /* SRWebView.swift in Sources */,
|
||||
3754ACEE2ED945A1009EBCAD /* Dictionary+SRAdd.swift in Sources */,
|
||||
03E9A7C92EC47177000D1067 /* AppDelegate.swift in Sources */,
|
||||
03E9A7FA2EC56D03000D1067 /* String+SRAdd.swift in Sources */,
|
||||
03B1A9192ECAF2E6006C353F /* SRHomePremiereNowView.swift in Sources */,
|
||||
@ -889,11 +991,13 @@
|
||||
03B1A9152ECAEE63006C353F /* SRHomeViralHitsCell.swift in Sources */,
|
||||
03B1A8472EC5CBCF006C353F /* SRViewController.swift in Sources */,
|
||||
370D2F052ED3FEE700571E77 /* SRHistoryCell.swift in Sources */,
|
||||
3754ACEA2ED94065009EBCAD /* SRBaseWebViewController + Script.swift in Sources */,
|
||||
03B1A9032EC8555B006C353F /* SRHomeYouLikeView.swift in Sources */,
|
||||
03B1A9362ECC1D1D006C353F /* SRSearchRecordView.swift in Sources */,
|
||||
03B1A8D82EC6D051006C353F /* SRCollectionView.swift in Sources */,
|
||||
03B1A90D2ECAC51A006C353F /* NSNumber+SRAdd.swift in Sources */,
|
||||
03E9A7DD2EC485E1000D1067 /* SRNetworkModel.swift in Sources */,
|
||||
3754ACEC2ED943AB009EBCAD /* SRAppWebViewController.swift in Sources */,
|
||||
03B1A9442ECC4ED9006C353F /* SRSearchResultView.swift in Sources */,
|
||||
3754ACBF2ED5B839009EBCAD /* SRNavgationTitleView.swift in Sources */,
|
||||
03B1A8FF2EC81C92006C353F /* SRImageView.swift in Sources */,
|
||||
@ -912,6 +1016,7 @@
|
||||
03B1A8E92EC721CD006C353F /* SRLabel.swift in Sources */,
|
||||
03B1A9282ECC05B1006C353F /* SRShortDetailModel.swift in Sources */,
|
||||
03980F592ECEED190006E317 /* SRMyShortViewController.swift in Sources */,
|
||||
3754ACD32ED82113009EBCAD /* SRGradientbutton.swift in Sources */,
|
||||
03B1A92A2ECC0738006C353F /* SRShortApi.swift in Sources */,
|
||||
03B1A90B2ECAB2EA006C353F /* SRHomeTopChartsContentView.swift in Sources */,
|
||||
370D2F0C2ED44ACB00571E77 /* SRListMenuDataSource.swift in Sources */,
|
||||
@ -929,6 +1034,7 @@
|
||||
03B1A9012EC852B2006C353F /* SRHomeModuleView.swift in Sources */,
|
||||
03E9A7EF2EC4A8AF000D1067 /* SRAccountManager.swift in Sources */,
|
||||
03B1A8F52EC81277006C353F /* SRHomeBannerView.swift in Sources */,
|
||||
3754ACDC2ED83F80009EBCAD /* SRHomeHistoryBottomView.swift in Sources */,
|
||||
03B1A9132ECAED04006C353F /* SRHomeViralHitsView.swift in Sources */,
|
||||
03B1A8DC2EC6D0EB006C353F /* SRHomeChildCell.swift in Sources */,
|
||||
03B1A8552EC5E434006C353F /* UIFont+SRAdd.swift in Sources */,
|
||||
@ -946,6 +1052,8 @@
|
||||
370D2F1C2ED4770800571E77 /* SRUserInfoModel.swift in Sources */,
|
||||
03B1A93C2ECC406E006C353F /* SRHotSearchView.swift in Sources */,
|
||||
03B1A8E32EC6F577006C353F /* SRHomeMenuCell.swift in Sources */,
|
||||
3754ACE12ED93C4D009EBCAD /* SRCoinPackController.swift in Sources */,
|
||||
3754ACD52ED82722009EBCAD /* SRDetailRecommendview.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@ -118,5 +118,4 @@ struct SRHomeApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -29,6 +29,20 @@ struct SRShortApi {
|
||||
}
|
||||
}
|
||||
|
||||
static func requestRecommand() async -> ([SRShortModel]?, Int?, String?) {
|
||||
await withCheckedContinuation { continuation in
|
||||
var param = SRNetwork.Parameters(path: "/getDetailsRecommand")
|
||||
param.method = .get
|
||||
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRNetwork.List<SRShortModel>>) in
|
||||
if response.isSuccess {
|
||||
continuation.resume(returning:(response.data?.list, response.code, response.msg))
|
||||
} else {
|
||||
continuation.resume(returning:(nil, response.code, response.msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func requestShortCollect(shortId: String, videoId: String?, isCollect: Bool) async -> Bool {
|
||||
await withCheckedContinuation { continuation in
|
||||
var path = ""
|
||||
|
||||
24
SynthReel/Base/Extension/Dictionary+SRAdd.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// Dictionary+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension Dictionary {
|
||||
|
||||
func toJsonString() -> String? {
|
||||
do {
|
||||
let data = try JSONSerialization.data(withJSONObject: self)
|
||||
let jsonStr = String(data: data, encoding: .utf8)
|
||||
return jsonStr
|
||||
} catch {
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
import UIKit
|
||||
import YYCategories
|
||||
import SmartCodable
|
||||
|
||||
extension String {
|
||||
|
||||
@ -24,3 +25,13 @@ extension String {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension String: SmartCodable {
|
||||
|
||||
static func timeZone() -> String {
|
||||
let timeZone = NSTimeZone.local as NSTimeZone
|
||||
let timeZoneSecondsFromGMT = timeZone.secondsFromGMT / 3600
|
||||
return String(format: "GMT+0%d:00", timeZoneSecondsFromGMT)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,18 @@ let SRWebBaseURL = "https://www.synthreeltv.com"
|
||||
let SRCampaignWebURL = "https://campaign.synthreeltv.com"
|
||||
|
||||
|
||||
|
||||
///反馈首页
|
||||
let kSRFeedBackHomeWebUrl = SRCampaignWebURL + "/pages/leave/index"
|
||||
///反馈列表
|
||||
let kSRFeedBackListWebUrl = SRCampaignWebURL + "/pages/leave/list"
|
||||
///反馈详情
|
||||
let kSRFeedBackDetailWebUrl = SRCampaignWebURL + "/pages/leave/detail"
|
||||
|
||||
///注销账号
|
||||
let kSRLogoutWebUrl = SRCampaignWebURL + "/pages/setting/logout"
|
||||
|
||||
let kSRRewardWebUrl = SRCampaignWebURL + "/pages/reward/theme4"
|
||||
/*
|
||||
SynthReel
|
||||
admin-api https://admin-api-synthreeltv.synthreeltv.com
|
||||
|
||||
45
SynthReel/Base/View/SRGradientbutton.swift
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// SRGradientbutton.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/27.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRGradientbutton: UIButton {
|
||||
|
||||
override class var layerClass: AnyClass {
|
||||
return CAGradientLayer.self
|
||||
}
|
||||
|
||||
var fa_gradientLayer: CAGradientLayer {
|
||||
return self.layer as! CAGradientLayer
|
||||
}
|
||||
|
||||
var fa_colors: [CGColor]? {
|
||||
didSet {
|
||||
fa_gradientLayer.colors = fa_colors
|
||||
}
|
||||
}
|
||||
|
||||
var fa_startPoint: CGPoint = .zero {
|
||||
didSet {
|
||||
fa_gradientLayer.startPoint = fa_startPoint
|
||||
}
|
||||
}
|
||||
|
||||
var fa_endPoint: CGPoint = .zero {
|
||||
didSet {
|
||||
fa_gradientLayer.endPoint = fa_endPoint
|
||||
}
|
||||
}
|
||||
|
||||
var fa_locations: [NSNumber] = [] {
|
||||
didSet {
|
||||
fa_gradientLayer.locations = fa_locations
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
83
SynthReel/Base/webview/SRAppWebViewController.swift
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// SRAppWebViewController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRAppWebViewController: SRBaseWebViewController {
|
||||
|
||||
|
||||
var id: String?
|
||||
|
||||
private var receiveDataCount = 0
|
||||
|
||||
var theme: String? = "theme_16"
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.autoTitle = false
|
||||
|
||||
if webUrl == kSRFeedBackListWebUrl {
|
||||
self.title = "synthreel_feedback_history".localized
|
||||
} else if webUrl == kSRFeedBackHomeWebUrl {
|
||||
self.title = "synthreel_feedback".localized
|
||||
} else if webUrl == kSRFeedBackDetailWebUrl {
|
||||
self.title = "synthreel_feedback_detail".localized
|
||||
} else if webUrl == kSRLogoutWebUrl {
|
||||
self.title = "synthreel_account_deletion".localized
|
||||
}else if webUrl == kSRRewardWebUrl {
|
||||
self.title = "Rewards".localized
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func fa_webViewDidFinishLoad(_ webView: SRWebView) {
|
||||
super.fa_webViewDidFinishLoad(webView)
|
||||
receiveDataCount = 0
|
||||
receiveDataFromNative()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRAppWebViewController {
|
||||
|
||||
func receiveDataFromNative() {
|
||||
receiveDataCount += 1
|
||||
if receiveDataCount > 10 { return }
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
var dic = [
|
||||
"token" : SRAccountManager.manager.token?.token ?? "",
|
||||
"time_zone" : String.timeZone(),
|
||||
// "lang" : FALanguageManager.manager.currentLanguageKey,
|
||||
"lang" : "en",
|
||||
"type" : "ios",
|
||||
"device-id" : SRDeviceId.shared.id
|
||||
]
|
||||
|
||||
if let theme = theme {
|
||||
dic["theme"] = theme
|
||||
}
|
||||
|
||||
if let id = id {
|
||||
dic["id"] = id
|
||||
}
|
||||
|
||||
if let json = dic.toJsonString() {
|
||||
let js = "receiveDataFromNative(\(json))"
|
||||
self.webView.evaluateJavaScript(js) { [weak self] _, error in
|
||||
guard let self = self else { return }
|
||||
if error != nil {
|
||||
self.receiveDataFromNative()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
112
SynthReel/Base/webview/SRBaseWebViewController + Script.swift
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// SRBaseWebViewController + Script.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import WebKit
|
||||
import ZLPhotoBrowser
|
||||
import SmartCodable
|
||||
|
||||
///APP交互
|
||||
let kSRWebMessageAPP = "js2app"
|
||||
///打开反馈列表
|
||||
let kSRWebMessageOpenFeedbackList = "openFeedbackList"
|
||||
///打开反馈详情
|
||||
let kSRWebMessageOpenFeedbackDetail = "openFeedbackDetail"
|
||||
///打开相册
|
||||
let kSRWebMessageOpenPhotoPicker = "openPhotoPicker"
|
||||
///删除账号成功
|
||||
let kSRWebMessageAccountDeletionFinish = "accountLogout"
|
||||
|
||||
extension SRBaseWebViewController {
|
||||
|
||||
func fa_webViewUserContentController(didReceive message: WKScriptMessage) {
|
||||
let name = message.name
|
||||
let body = message.body
|
||||
|
||||
switch name {
|
||||
case kSRWebMessageOpenFeedbackList:
|
||||
let vc = SRAppWebViewController()
|
||||
vc.webUrl = kSRFeedBackListWebUrl
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case kSRWebMessageOpenFeedbackDetail:
|
||||
guard let body = body as? [String : Any] else { return }
|
||||
guard let id = body["id"] as? Int else { return }
|
||||
|
||||
let vc = SRAppWebViewController()
|
||||
vc.id = "\(id)"
|
||||
vc.webUrl = kSRFeedBackDetailWebUrl
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case kSRWebMessageOpenPhotoPicker:
|
||||
openPhotoPicker()
|
||||
|
||||
case kSRWebMessageAPP:
|
||||
guard let body = message.body as? [String : Any] else { return }
|
||||
guard let model = SRWebMessageModel.deserialize(from: body) else { return }
|
||||
let type = model.type
|
||||
let data = model.data
|
||||
|
||||
if type == "login" {
|
||||
// let view = FALoginView()
|
||||
// view.present(in: nil)
|
||||
|
||||
} else if type == "open_notify" {
|
||||
// openNotify()
|
||||
|
||||
} else if type == "watch_video" {
|
||||
let vc = SRDetailPlayerViewController()
|
||||
vc.shortId = data?.short_play_id
|
||||
// vc.activityId = data?.activity_id
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
} else {
|
||||
|
||||
guard let urlStr = data?.link else { return }
|
||||
guard let url = URL(string: urlStr) else { return }
|
||||
if UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
case kSRWebMessageAccountDeletionFinish:
|
||||
self.navigationController?.popToRootViewController(animated: true)
|
||||
// NotificationCenter.default.post(name: FALogin.loginStatusChangeNotification, object: nil)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
///打开相册
|
||||
private func openPhotoPicker() {
|
||||
|
||||
ZLPhotoConfiguration.default().allowSelectOriginal = false
|
||||
ZLPhotoConfiguration.default().maxSelectCount = 1
|
||||
ZLPhotoConfiguration.default().allowEditImage = false
|
||||
ZLPhotoConfiguration.default().allowSelectVideo = false
|
||||
ZLPhotoConfiguration.default().allowSelectGif = false
|
||||
ZLPhotoConfiguration.default().allowTakePhotoInLibrary = false
|
||||
|
||||
let picker = ZLPhotoPicker()
|
||||
picker.selectImageBlock = { [weak self] (results, _) in
|
||||
guard let self = self else { return }
|
||||
guard let image = results.first?.image else { return }
|
||||
guard let imageData = image.jpegData(compressionQuality: 0.8) else { return }
|
||||
let imageDataStr = imageData.base64EncodedString(options: .endLineWithCarriageReturn)
|
||||
|
||||
let js = "uploadConvertImage('\(imageDataStr)')"
|
||||
self.webView.evaluateJavaScript(js)
|
||||
}
|
||||
|
||||
picker.showPhotoLibrary(sender: self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
114
SynthReel/Base/webview/SRBaseWebViewController.swift
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// SRBaseWebViewController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import WebKit
|
||||
|
||||
|
||||
class SRBaseWebViewController: SRViewController {
|
||||
|
||||
var webUrl: String?
|
||||
|
||||
///自动设置标题
|
||||
var autoTitle = true
|
||||
|
||||
var needAutoRefresh = true
|
||||
|
||||
private(set) lazy var webView: SRWebView = {
|
||||
let controller = WKUserContentController()
|
||||
|
||||
let config = WKWebViewConfiguration()
|
||||
config.userContentController = controller
|
||||
config.preferences.javaScriptEnabled = true
|
||||
/** 默认是不能通过JS自动打开窗口的,必须通过用户交互才能打开 */
|
||||
config.preferences.javaScriptCanOpenWindowsAutomatically = true
|
||||
let webView = SRWebView(frame: self.view.bounds, configuration: config)
|
||||
webView.delegate = self
|
||||
return webView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// self.edgesForExtendedLayout = []
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
if let url = webUrl {
|
||||
self.load(webUrl: url)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
// self.fa_setNavigationStyle()
|
||||
}
|
||||
|
||||
func load(webUrl: String) {
|
||||
let str: String = webUrl
|
||||
|
||||
guard let url = URL(string: str) else { return }
|
||||
let request = URLRequest(url: url, timeoutInterval: 30)
|
||||
|
||||
self.webView.load(request)
|
||||
}
|
||||
|
||||
func reload() {
|
||||
self.webView.reload()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRBaseWebViewController {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
self.view.addSubview(webView)
|
||||
|
||||
self.webView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(0)
|
||||
make.right.equalToSuperview().offset(0)
|
||||
make.bottom.equalToSuperview().offset(0)
|
||||
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- VPWebViewDelegate --------------
|
||||
extension SRBaseWebViewController: SRWebViewDelegate {
|
||||
|
||||
func fa_webView(_ webView: SRWebView, shouldStartLoadWith navigationAction: WKNavigationAction) -> Bool {
|
||||
self.webView.isHidden = false
|
||||
return true
|
||||
}
|
||||
|
||||
func fa_webViewDidStartLoad(_ webView: SRWebView) {
|
||||
SRHud.show(containerView: self.view)
|
||||
}
|
||||
|
||||
func fa_webView(webView: SRWebView, didChangeTitle title: String) {
|
||||
if autoTitle {
|
||||
self.title = title
|
||||
}
|
||||
}
|
||||
|
||||
func fa_webViewDidFinishLoad(_ webView: SRWebView) {
|
||||
self.webView.isHidden = false
|
||||
SRHud.dismiss()
|
||||
}
|
||||
|
||||
func fa_webView(_ webView: SRWebView, didFailLoadWithError error: any Error) {
|
||||
SRHud.dismiss()
|
||||
}
|
||||
|
||||
func fa_userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
self.fa_webViewUserContentController(didReceive: message)
|
||||
}
|
||||
}
|
||||
26
SynthReel/Base/webview/SRWebMessageModel.swift
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// SRWebMessageModel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
|
||||
struct SRWebMessageModel: SmartCodable {
|
||||
var type: String?
|
||||
|
||||
var data: SRWebMessageData?
|
||||
|
||||
}
|
||||
|
||||
struct SRWebMessageData: SmartCodable {
|
||||
|
||||
var activity_id: String?
|
||||
var short_play_id: String?
|
||||
var link: String?
|
||||
|
||||
}
|
||||
153
SynthReel/Base/webview/SRWebView.swift
Normal file
@ -0,0 +1,153 @@
|
||||
//
|
||||
// SRWebView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@preconcurrency import WebKit
|
||||
import YYText
|
||||
|
||||
@objc protocol SRWebViewDelegate: NSObjectProtocol {
|
||||
|
||||
@objc optional func fa_webView(_ webView: SRWebView, shouldStartLoadWith navigationAction: WKNavigationAction) -> Bool
|
||||
|
||||
@objc optional func fa_webViewDidStartLoad(_ webView: SRWebView)
|
||||
|
||||
@objc optional func fa_webViewDidFinishLoad(_ webView: SRWebView)
|
||||
|
||||
@objc optional func fa_webView(_ webView: SRWebView, didFailLoadWithError error: Error)
|
||||
|
||||
///进度
|
||||
@objc optional func fa_webView(webView: SRWebView, didChangeProgress progress: CGFloat)
|
||||
///标题
|
||||
@objc optional func fa_webView(webView: SRWebView, didChangeTitle title: String)
|
||||
|
||||
///web交互用
|
||||
@objc optional func fa_userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
|
||||
|
||||
}
|
||||
|
||||
class SRWebView: WKWebView {
|
||||
|
||||
weak var delegate: SRWebViewDelegate?
|
||||
|
||||
private(set) var scriptMessageHandlerArray: [String] = [
|
||||
kSRWebMessageAPP,
|
||||
kSRWebMessageOpenFeedbackList,
|
||||
kSRWebMessageOpenFeedbackDetail,
|
||||
kSRWebMessageOpenPhotoPicker,
|
||||
kSRWebMessageAccountDeletionFinish,
|
||||
]
|
||||
|
||||
|
||||
deinit {
|
||||
self.removeObserver(self, forKeyPath: "estimatedProgress")
|
||||
self.removeObserver(self, forKeyPath: "title")
|
||||
|
||||
}
|
||||
|
||||
override init(frame: CGRect, configuration: WKWebViewConfiguration) {
|
||||
super.init(frame: frame, configuration: configuration)
|
||||
addScriptMessageHandler()
|
||||
_setupInit()
|
||||
}
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
private func _setupInit() {
|
||||
|
||||
self.isOpaque = false
|
||||
self.navigationDelegate = self
|
||||
self.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
|
||||
self.addObserver(self, forKeyPath: "title", options: .new, context: nil)
|
||||
|
||||
}
|
||||
|
||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
if object as? SRWebView == self {
|
||||
if keyPath == "estimatedProgress", let progress = change?[NSKeyValueChangeKey.newKey] as? CGFloat {
|
||||
self.delegate?.fa_webView?(webView: self, didChangeProgress: progress)
|
||||
} else if keyPath == "title", let title = change?[NSKeyValueChangeKey.newKey] as? String {
|
||||
self.delegate?.fa_webView?(webView: self, didChangeTitle: title)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func load(urlStr: String) {
|
||||
guard let url = URL(string: urlStr) else { return }
|
||||
let request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 30)
|
||||
self.load(request)
|
||||
}
|
||||
|
||||
func removeScriptMessageHandler() {
|
||||
self.scriptMessageHandlerArray.forEach{
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: $0)
|
||||
}
|
||||
}
|
||||
func addScriptMessageHandler() {
|
||||
self.scriptMessageHandlerArray.forEach{
|
||||
configuration.userContentController.add(YYTextWeakProxy(target: self) as! WKScriptMessageHandler, name: $0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK:-------------- WKNavigationDelegate --------------
|
||||
extension SRWebView: WKNavigationDelegate {
|
||||
|
||||
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
|
||||
|
||||
decisionHandler(.allow);
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||
|
||||
if let url = navigationAction.request.url,
|
||||
url.scheme != "http",
|
||||
url.scheme != "https"
|
||||
{
|
||||
UIApplication.shared.open(url)
|
||||
decisionHandler(.cancel)
|
||||
return
|
||||
}
|
||||
|
||||
if let result = self.delegate?.fa_webView?(self, shouldStartLoadWith: navigationAction) {
|
||||
if result {
|
||||
decisionHandler(.allow)
|
||||
} else {
|
||||
decisionHandler(.cancel)
|
||||
}
|
||||
} else {
|
||||
decisionHandler(.allow)
|
||||
}
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
||||
self.delegate?.fa_webViewDidStartLoad?(self)
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
self.delegate?.fa_webViewDidFinishLoad?(self)
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
||||
self.delegate?.fa_webView?(self, didFailLoadWithError: error)
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||||
self.delegate?.fa_webView?(self, didFailLoadWithError: error)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MARK:-------------- WKScriptMessageHandler --------------
|
||||
extension SRWebView: WKScriptMessageHandler {
|
||||
|
||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
self.delegate?.fa_userContentController?(userContentController, didReceive: message)
|
||||
}
|
||||
|
||||
}
|
||||
30
SynthReel/Class/Coinpack/VC/SRCoinPackController.swift
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// SRCoinPackController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRCoinPackController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
// Get the new view controller using segue.destination.
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
143
SynthReel/Class/Home/V/SRHomeHistoryBottomView.swift
Normal file
@ -0,0 +1,143 @@
|
||||
//
|
||||
// SRHomeHistoryBottomView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/27.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRHomeHistoryBottomView: UIView {
|
||||
|
||||
var model: SRShortModel? {
|
||||
didSet {
|
||||
coverImageView.sr_setImage(model?.image_url)
|
||||
titleLabel.text = model?.name
|
||||
let text = String(format: "EP. %@ / EP. %d", model?.current_episode ?? "0", model?.episode_total ?? 0)
|
||||
setEpisodeText(text)
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var coverImageView: SRImageView = {
|
||||
let imageView = SRImageView()
|
||||
imageView.layer.cornerRadius = 21
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var bgView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
view.image = .recordBottomBg
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var playView: UIImageView = {
|
||||
let imageView = UIImageView(image: .recordBottomArrow)
|
||||
imageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var epLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 10, weight: .regular)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
fa_setupLayout()
|
||||
|
||||
let tap = UITapGestureRecognizer(target: self, action: #selector(handleBg))
|
||||
addGestureRecognizer(tap)
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc func handleBg() {
|
||||
let vc = SRDetailPlayerViewController()
|
||||
vc.shortId = self.model?.short_play_id
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
func setEpisodeText(_ text: String) {
|
||||
let full = text as NSString
|
||||
|
||||
let parts = text.components(separatedBy: " / ")
|
||||
guard parts.count == 2 else {
|
||||
epLabel.text = text
|
||||
return
|
||||
}
|
||||
|
||||
let front = parts[0] + " "
|
||||
let frontLen = (front as NSString).length
|
||||
let fullLen = full.length
|
||||
|
||||
let attr = NSMutableAttributedString(string: text)
|
||||
|
||||
// 前段(白色)
|
||||
attr.yy_setColor(.srBlue, range: NSRange(location: 0, length: frontLen))
|
||||
attr.yy_setFont(.systemFont(ofSize: 12), range: NSRange(location: 0, length: frontLen))
|
||||
|
||||
// 后段(灰色)
|
||||
attr.yy_setColor(UIColor.white, range: NSRange(location: frontLen, length: fullLen - frontLen))
|
||||
attr.yy_setFont(.systemFont(ofSize: 12), range: NSRange(location: frontLen, length: fullLen - frontLen))
|
||||
|
||||
epLabel.attributedText = attr
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension SRHomeHistoryBottomView {
|
||||
private func fa_setupLayout() {
|
||||
addSubview(bgView)
|
||||
addSubview(coverImageView)
|
||||
bgView.addSubview(playView)
|
||||
bgView.addSubview(titleLabel)
|
||||
bgView.addSubview(epLabel)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(1)
|
||||
make.height.equalTo(57)
|
||||
}
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(25)
|
||||
make.width.equalTo(42)
|
||||
make.height.equalTo(42)
|
||||
}
|
||||
|
||||
playView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-28)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(coverImageView.snp.right).offset(10)
|
||||
make.top.equalToSuperview().offset(12)
|
||||
make.right.lessThanOrEqualTo(playView.snp.left).offset(-10)
|
||||
}
|
||||
|
||||
epLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(titleLabel)
|
||||
make.bottom.equalToSuperview().offset(-12)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -110,6 +110,13 @@ class SRHomeViewController: SRViewController {
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
private lazy var playHistoryView: SRHomeHistoryBottomView = {
|
||||
let view = SRHomeHistoryBottomView()
|
||||
view.isHidden = true
|
||||
return view
|
||||
}()
|
||||
|
||||
deinit {
|
||||
srPrint(message: "销毁")
|
||||
}
|
||||
@ -121,7 +128,6 @@ class SRHomeViewController: SRViewController {
|
||||
|
||||
Task {
|
||||
await requestModuleList()
|
||||
// await requestCategoryList()
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,6 +146,8 @@ class SRHomeViewController: SRViewController {
|
||||
vc.handleHeaderRefresh(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -153,6 +161,7 @@ extension SRHomeViewController {
|
||||
menuContentView.addSubview(menuView)
|
||||
menuContentView.addSubview(moreButton)
|
||||
moreButton.addSubview(moreTitleLabel)
|
||||
view.addSubview(playHistoryView)
|
||||
// moreButton.addSubview(moreIconImageView)
|
||||
|
||||
menuView.listContainer = pageView.listContainerView
|
||||
@ -197,6 +206,11 @@ extension SRHomeViewController {
|
||||
make.left.equalToSuperview()
|
||||
}
|
||||
|
||||
playHistoryView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(16)
|
||||
make.centerX.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
}
|
||||
// moreIconImageView.snp.makeConstraints { make in
|
||||
// make.centerY.equalToSuperview()
|
||||
// make.right.equalToSuperview()
|
||||
@ -274,8 +288,17 @@ extension SRHomeViewController {
|
||||
self.menuDataSource.titles = self.viewModel.categoryTitleArr
|
||||
self.pageView.reloadData()
|
||||
self.menuView.reloadData()
|
||||
await self.requestHistory()
|
||||
}
|
||||
|
||||
|
||||
func requestHistory() async {
|
||||
await self.viewModel.requestHistoryData()
|
||||
if let playHistory = self.viewModel.historyModel {
|
||||
self.playHistoryView.model = playHistory
|
||||
self.playHistoryView.isHidden = false
|
||||
} else {
|
||||
self.playHistoryView.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,8 @@ class SRHomeViewModel: NSObject {
|
||||
lazy var categoryArr: [SRShortModel] = []
|
||||
lazy var categoryTitleArr: [String] = []
|
||||
|
||||
var historyModel: SRShortModel?
|
||||
|
||||
lazy var moduleArr: [SRHomeModuleItem] = []
|
||||
|
||||
// func requestCategoryList() async {
|
||||
@ -26,6 +28,17 @@ class SRHomeViewModel: NSObject {
|
||||
// }
|
||||
// }
|
||||
|
||||
func requestHistoryData() async {
|
||||
let listmodel = await SRHomeApi.requestHistoryData(page: 1)
|
||||
if let model = listmodel?.first {
|
||||
historyModel = model
|
||||
} else {
|
||||
historyModel = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func requestModuleList() async {
|
||||
guard let list = await SRHomeApi.requestHomeModulesData() else { return }
|
||||
|
||||
|
||||
79
SynthReel/Class/Player/V/SRDetailRecommendCell.swift
Normal file
@ -0,0 +1,79 @@
|
||||
//
|
||||
// SRDetailRecommendCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/27.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FSPagerView
|
||||
import JXPlayer
|
||||
|
||||
class SRDetailRecommendCell: FSPagerViewCell {
|
||||
|
||||
var model: SRShortModel? {
|
||||
didSet {
|
||||
player.coverImageView?.sr_setImage(model?.image_url)
|
||||
player.setPlayUrl(url: model?.video_url ?? "")
|
||||
}
|
||||
}
|
||||
|
||||
/// ① 新增背景图
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let iv = UIImageView()
|
||||
iv.image = .homeViralHitsCell
|
||||
iv.contentMode = .scaleAspectFill
|
||||
iv.clipsToBounds = true
|
||||
return iv
|
||||
}()
|
||||
|
||||
|
||||
private lazy var player: JXPlayer = {
|
||||
let player = JXPlayer(controlView: nil)
|
||||
player.playerView = self.playerView
|
||||
player.isLoop = true
|
||||
return player
|
||||
}()
|
||||
|
||||
private lazy var playerView: UIView = {
|
||||
let view = UIView()
|
||||
view.isUserInteractionEnabled = false
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
contentView.addSubview(bgImageView)
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
// 播放器画面
|
||||
contentView.addSubview(playerView)
|
||||
playerView.snp.makeConstraints { make in
|
||||
// make.edges.equalToSuperview()
|
||||
make.edges.equalTo(UIEdgeInsets(top: 15, left: 8, bottom: 15, right: 8))
|
||||
}
|
||||
// addSubview(playerView)
|
||||
//
|
||||
// playerView.snp.makeConstraints { make in
|
||||
// make.edges.equalToSuperview()
|
||||
// }
|
||||
}
|
||||
|
||||
@MainActor required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func play() {
|
||||
self.player.start()
|
||||
}
|
||||
|
||||
func pause() {
|
||||
self.player.pause()
|
||||
}
|
||||
|
||||
}
|
||||
175
SynthReel/Class/Player/V/SRDetailRecommendview.swift
Normal file
@ -0,0 +1,175 @@
|
||||
//
|
||||
// SRDetailRecommendview.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/27.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FSPagerView
|
||||
|
||||
class SRDetailRecommendview: SRBaseAlert {
|
||||
|
||||
var clickCloseButton: (() -> Void)?
|
||||
var didSelectedVideo: ((_ model: SRShortModel) -> Void)?
|
||||
|
||||
var dataArr: [SRShortModel] = [] {
|
||||
didSet {
|
||||
self.pagerView.reloadData()
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
|
||||
self?.updateCurrentData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private weak var currentCell: SRDetailRecommendCell? {
|
||||
didSet {
|
||||
oldValue?.pause()
|
||||
|
||||
currentCell?.play()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var titleLabel: SRLabel = {
|
||||
let label = SRLabel()
|
||||
label.font = .font(ofSize: 16, weight: .init(900))
|
||||
label.textColors = [UIColor._4_CFFD_4.cgColor, UIColor._51_D_4_FF.cgColor]
|
||||
label.textStartPoint = .init(x: 0.5, y: 0)
|
||||
label.textEndPoint = .init(x: 0.5, y: 1)
|
||||
label.text = "Keep the Drama Going".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var bgView: UIImageView = {
|
||||
let view = UIImageView(image: UIImage(named: "recommendBg"))
|
||||
view.isUserInteractionEnabled = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var cancelButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "Close"), for: .normal)
|
||||
button.addTarget(self, action: #selector(handleCancelButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var pagerView: FSPagerView = {
|
||||
let transformer = SRPagerViewTransformer(type: .linear)
|
||||
transformer.minimumScale = 1
|
||||
|
||||
let view = FSPagerView()
|
||||
view.itemSize = .init(width: 132, height: 185)
|
||||
view.transformer = transformer
|
||||
view.delegate = self
|
||||
view.dataSource = self
|
||||
view.isInfinite = true
|
||||
view.interitemSpacing = 8
|
||||
view.register(SRDetailRecommendCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
contentWidth = UIScreen.width
|
||||
self.closeButton.isHidden = true
|
||||
|
||||
self.contentView.backgroundColor = .clear
|
||||
self.contentView.layer.cornerRadius = 0
|
||||
self.contentView.layer.masksToBounds = false
|
||||
|
||||
fa_setupLayout()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
@objc private func handleCancelButton() {
|
||||
self.dismiss()
|
||||
self.clickCloseButton?()
|
||||
}
|
||||
|
||||
///更新当前数据
|
||||
private func updateCurrentData() {
|
||||
guard let cell = self.pagerView.cellForItem(at: self.pagerView.currentIndex) as? SRDetailRecommendCell else { return }
|
||||
|
||||
self.currentCell = cell
|
||||
// let model = cell.model
|
||||
// self.videoNameLabel.text = model?.name
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRDetailRecommendview {
|
||||
|
||||
private func fa_setupLayout() {
|
||||
contentView.addSubview(bgView)
|
||||
contentView.addSubview(cancelButton)
|
||||
bgView.addSubview(titleLabel)
|
||||
bgView.addSubview(pagerView)
|
||||
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview().inset(15)
|
||||
make.top.equalToSuperview().offset(-25)
|
||||
// make.bottom.e()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(17)
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
|
||||
pagerView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview().inset(10)
|
||||
make.bottom.equalTo(-17)
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(10)
|
||||
}
|
||||
|
||||
cancelButton.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(bgView.snp.bottom).offset(30)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: FSPagerViewDelegate FSPagerViewDataSource
|
||||
extension SRDetailRecommendview: FSPagerViewDelegate, FSPagerViewDataSource {
|
||||
|
||||
func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
|
||||
let cell = pagerView.dequeueReusableCell(withReuseIdentifier: "cell", at: index) as! SRDetailRecommendCell
|
||||
cell.model = self.dataArr[index]
|
||||
return cell
|
||||
}
|
||||
|
||||
func numberOfItems(in pagerView: FSPagerView) -> Int {
|
||||
return self.dataArr.count
|
||||
}
|
||||
|
||||
func pagerView(_ pagerView: FSPagerView, didSelectItemAt index: Int) {
|
||||
didSelectedVideo?(self.dataArr[index])
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
func pagerViewDidEndDecelerating(_ pagerView: FSPagerView) {
|
||||
self.updateCurrentData()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRDetailRecommendview {
|
||||
|
||||
class PageControl: UIPageControl{
|
||||
override func size(forNumberOfPages pageCount: Int) -> CGSize {
|
||||
return .init(width: 4, height: 4)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -33,7 +33,7 @@ class SRDetailPlayerViewController: JXPlayerListViewController {
|
||||
lazy var returnButton: UIButton = {
|
||||
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.sr_handleNavigationBack()
|
||||
self.handleBackButton()
|
||||
}))
|
||||
button.setImage(UIImage(named: "arrow_left_icon_01"), for: .normal)
|
||||
return button
|
||||
@ -54,6 +54,7 @@ class SRDetailPlayerViewController: JXPlayerListViewController {
|
||||
|
||||
Task {
|
||||
await self.sr_viewModel.requestShortDetail()
|
||||
await self.sr_viewModel.requsetRecommandData()
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,6 +76,30 @@ class SRDetailPlayerViewController: JXPlayerListViewController {
|
||||
await SRShortApi.requestCreatePlayHistory(shortId: videoInfo?.short_play_id, videoId: videoInfo?.short_play_video_id)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func handleBackButton() {
|
||||
self.pause()
|
||||
|
||||
if !self.sr_viewModel.recommandList.isEmpty, self.sr_viewModel.isShowRecommand {
|
||||
let view = SRDetailRecommendview()
|
||||
view.dataArr = self.sr_viewModel.recommandList
|
||||
view.clickCloseButton = { [weak self] in
|
||||
self?.sr_handleNavigationBack()
|
||||
}
|
||||
view.didSelectedVideo = { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
self.shortId = model.short_play_id
|
||||
Task {
|
||||
await self.sr_viewModel.requestShortDetail()
|
||||
}
|
||||
}
|
||||
view.show(in: SRTool.keyWindow)
|
||||
} else {
|
||||
self.sr_handleNavigationBack()
|
||||
}
|
||||
|
||||
// self.handleNavigationBack()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -115,3 +140,4 @@ extension SRDetailPlayerViewController: JXPlayerListViewControllerDelegate, JXPl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
import UIKit
|
||||
import JXPlayer
|
||||
import YYText
|
||||
import HWPanModal
|
||||
|
||||
class SRShortPlayerViewModel: JXPlayerListViewModel {
|
||||
@ -16,6 +17,12 @@ class SRShortPlayerViewModel: JXPlayerListViewModel {
|
||||
|
||||
var dataArr: [SRShortDetailModel] = []
|
||||
|
||||
var recommandList: [SRShortModel] = []
|
||||
|
||||
///是否展示推荐数据
|
||||
private(set) var isShowRecommand = false
|
||||
private var recommandTimer: Timer?
|
||||
|
||||
weak var popView: UIView?
|
||||
|
||||
nonisolated required init() {
|
||||
@ -47,7 +54,10 @@ class SRShortPlayerViewModel: JXPlayerListViewModel {
|
||||
targetIndexPath = .init(row: row, section: 0)
|
||||
}
|
||||
}
|
||||
|
||||
isShowRecommand = false
|
||||
recommandTimer?.invalidate()
|
||||
recommandTimer = nil
|
||||
recommandTimer = Timer.scheduledTimer(timeInterval: 6, target: YYTextWeakProxy(target: self), selector: #selector(handleRecommandTimer), userInfo: nil, repeats: false)
|
||||
self.playerListVC?.scrollToItem(indexPath: targetIndexPath, animated: false)
|
||||
}
|
||||
return code
|
||||
@ -69,4 +79,15 @@ extension SRShortPlayerViewModel {
|
||||
self.popView = view
|
||||
}
|
||||
|
||||
func requsetRecommandData() async {
|
||||
let (model, _, _) = await SRShortApi.requestRecommand()
|
||||
guard let model = model else { return }
|
||||
self.recommandList = model
|
||||
}
|
||||
|
||||
@objc private func handleRecommandTimer() {
|
||||
self.isShowRecommand = true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
91
SynthReel/Class/User/VC/SRFeedBackController.swift
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// SRFeedBackController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRFeedBackController: SRAppWebViewController {
|
||||
|
||||
|
||||
private lazy var rightButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "feedList"), for: .normal)
|
||||
button.addTarget(self, action: #selector(handleRightBarButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var redView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .FF_9_F_4_C
|
||||
view.layer.cornerRadius = 8
|
||||
view.isHidden = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var redLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 12, weight: .bold)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
self.webUrl = kSRFeedBackHomeWebUrl
|
||||
super.viewDidLoad()
|
||||
|
||||
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Frame 2085663258"), style: .plain, target: self, action: #selector(handleRightBarButton))
|
||||
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightButton)
|
||||
|
||||
|
||||
rightButton.addSubview(redView)
|
||||
redView.addSubview(redLabel)
|
||||
|
||||
redView.snp.makeConstraints { make in
|
||||
make.height.equalTo(16)
|
||||
make.width.greaterThanOrEqualTo(16)
|
||||
make.top.equalToSuperview().offset(-8)
|
||||
make.right.equalToSuperview().offset(8)
|
||||
}
|
||||
|
||||
redLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
make.left.greaterThanOrEqualToSuperview().offset(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
// self.requestRedCount()
|
||||
}
|
||||
|
||||
@objc private func handleRightBarButton() {
|
||||
|
||||
let vc = SRAppWebViewController()
|
||||
vc.webUrl = kSRFeedBackListWebUrl
|
||||
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension SRFeedBackController {
|
||||
|
||||
// private func requestRedCount() {
|
||||
// FAAPI.requestFeedbackRedCount { [weak self] model in
|
||||
// guard let self = self else { return }
|
||||
// if let count = model?.feedback_notice_num, count > 0 {
|
||||
// self.redView.isHidden = false
|
||||
// self.redLabel.text = "\(count)"
|
||||
// } else {
|
||||
// self.redView.isHidden = true
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
}
|
||||
21
SynthReel/Class/User/VC/SRRewardController.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// SRRewardController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/28.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRRewardController: SRAppWebViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
self.webUrl = kSRRewardWebUrl
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -96,6 +96,13 @@ extension SRUserViewController: UICollectionViewDelegate, UICollectionViewDataSo
|
||||
let aboutvc = SRAboutUsController ();
|
||||
self.navigationController?.pushViewController(aboutvc, animated: true)
|
||||
break
|
||||
case .feedback:
|
||||
// let vc = SRFeedBackController ();
|
||||
// self.navigationController?.pushViewController(vc, animated: true)
|
||||
let vc = SRRewardController ()
|
||||
vc.theme = "theme_15"
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
break
|
||||
case .privacyPolicy:
|
||||
if let url = URL(string: SRWebBaseURL + "/private") {
|
||||
UIApplication.shared.open(url)
|
||||
@ -142,7 +149,7 @@ extension SRUserViewController {
|
||||
private func setDataArr() {
|
||||
|
||||
let arr = [
|
||||
// SRUserSettingModel(type: .feedback, name: "synthreel_feedback".localized, icon: UIImage(named: "icon_feedback")),
|
||||
SRUserSettingModel(type: .feedback, name: "synthreel_feedback".localized, icon: UIImage(named: "icon_feedback")),
|
||||
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")),
|
||||
|
||||
@ -23,8 +23,8 @@ struct SRUserSettingModel {
|
||||
// case purchaseRecords
|
||||
// ///金币奖励
|
||||
// case rewardCoins
|
||||
// case deleteAccount
|
||||
// case language
|
||||
case deleteAccount
|
||||
case language
|
||||
}
|
||||
|
||||
|
||||
|
||||
166
SynthReel/Libs/Alert/SRBaseAlert.swift
Normal file
@ -0,0 +1,166 @@
|
||||
//
|
||||
// SRBaseAlert.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/27.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SRBaseAlert: UIView {
|
||||
|
||||
var clickHighlightButton: (() -> Void)?
|
||||
|
||||
var contentWidth: CGFloat = UIScreen.width - 70 {
|
||||
didSet {
|
||||
containerView.snp.updateConstraints { make in
|
||||
make.width.equalTo(contentWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var containerView: UIView = {
|
||||
let view = UIView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private(set) var contentView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = ._404040
|
||||
view.layer.cornerRadius = 16
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private(set) lazy var closeButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "close_icon_03"), for: .normal)
|
||||
button.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
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)
|
||||
button.addTarget(self, action: #selector(handleHighlightButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = ._000000.withAlphaComponent(0.5)
|
||||
|
||||
addSubview(containerView)
|
||||
containerView.addSubview(contentView)
|
||||
containerView.addSubview(closeButton)
|
||||
|
||||
containerView.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
make.width.equalTo(contentWidth)
|
||||
}
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-66)
|
||||
}
|
||||
|
||||
closeButton.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@objc func show(in view: UIView? = nil) -> Self {
|
||||
guard self.superview == nil else { return self }
|
||||
|
||||
var inView: UIView
|
||||
if let view = view {
|
||||
inView = view
|
||||
} else {
|
||||
inView = SRBaseAlert.Window.manager.createWindow()
|
||||
}
|
||||
|
||||
inView.addSubview(self)
|
||||
self.frame = inView.bounds
|
||||
showAnimation()
|
||||
|
||||
return self
|
||||
}
|
||||
@objc func dismiss() {
|
||||
dismissAnimation()
|
||||
}
|
||||
|
||||
@objc func handleHighlightButton() {
|
||||
self.dismissAnimation()
|
||||
self.clickHighlightButton?()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SRBaseAlert {
|
||||
private func showAnimation() {
|
||||
containerView.transform = CGAffineTransform(translationX: 0, y: 200)
|
||||
|
||||
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0) {
|
||||
self.containerView.transform = CGAffineTransform.identity
|
||||
}
|
||||
}
|
||||
|
||||
private func dismissAnimation() {
|
||||
|
||||
UIView.animate(withDuration: 0.3) {
|
||||
self.alpha = 0
|
||||
self.containerView.transform = CGAffineTransform(translationX: 0, y: 500)
|
||||
} completion: { _ in
|
||||
self.removeFromSuperview()
|
||||
SRBaseAlert.Window.manager.dismissWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SRBaseAlert {
|
||||
class Window {
|
||||
static let manager = Window()
|
||||
|
||||
private(set) var window: UIWindow?
|
||||
|
||||
func createWindow() -> UIWindow {
|
||||
guard let window = window else {
|
||||
let window = UIWindow(windowScene: SRTool.windowScene!)
|
||||
window.backgroundColor = .clear
|
||||
window.windowLevel = .alert
|
||||
window.isHidden = false
|
||||
self.window = window
|
||||
return window
|
||||
}
|
||||
return window
|
||||
}
|
||||
|
||||
func dismissWindow() {
|
||||
guard let window = self.window else { return }
|
||||
|
||||
var isHidden = true
|
||||
|
||||
window.subviews.forEach {
|
||||
if $0.isKind(of: SRBaseAlert.self) {
|
||||
isHidden = false
|
||||
}
|
||||
}
|
||||
if isHidden {
|
||||
window.isHidden = true
|
||||
self.window = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
SynthReel/Libs/FSPagerView/SRPagerViewTransformer.swift
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// SRPagerViewTransformer.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/27.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FSPagerView
|
||||
|
||||
class SRPagerViewTransformer: FSPagerViewTransformer {
|
||||
|
||||
override func proposedInteritemSpacing() -> CGFloat {
|
||||
guard let pagerView = self.pagerView else {
|
||||
return 0
|
||||
}
|
||||
return pagerView.interitemSpacing
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x00",
|
||||
"green" : "0x00",
|
||||
"red" : "0x00"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x40",
|
||||
"green" : "0x40",
|
||||
"red" : "0x40"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x4C",
|
||||
"green" : "0x9F",
|
||||
"red" : "0xFF"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
SynthReel/Source/Assets.xcassets/Image/feedList.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "feedList@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "feedList@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 617 B |
22
SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "recordBottomArrow@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "recordBottomArrow@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
22
SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "recordBottomBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "recordBottomBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Close@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Close@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "recommendBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "recommendBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 121 KiB |
22
SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "suerButtonBg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "suerButtonBg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
@ -23,13 +23,17 @@
|
||||
"Select Episode" = "Select Episode";
|
||||
"all_episodes_text" = "(All ## episodes)";
|
||||
"recommend_ep_text" = "Watch the complete series";
|
||||
"synthreel_feedback" = "Help Center";
|
||||
"synthreel_about_us" = "About Us";
|
||||
"synthreel_privacy_policy" = "Privacy Policy";
|
||||
"synthreel_user_agreement" = "User Agreement";
|
||||
"synthreel_visit_website" = "visit website";
|
||||
"Viral Hits" = "Viral Hits";
|
||||
"Live Trending Rankings" = "Live Trending Rankings";
|
||||
|
||||
"empty_title_01" = "No search results";
|
||||
"empty_title_02" = "There is no data for the moment.";
|
||||
"Keep the Drama Going" = "Keep the Drama Going";
|
||||
"synthreel_feedback" = "FeedBack";
|
||||
"synthreel_feedback_history" = "Feedback History";
|
||||
"synthreel_feedback_detail" = "Feedback Details";
|
||||
"synthreel_account_deletion" = "Account Deletion";
|
||||
"Rewards" = "Rewards";
|
||||
|
||||