diff --git a/Podfile b/Podfile index 179b344..50e7ff7 100644 --- a/Podfile +++ b/Podfile @@ -32,4 +32,5 @@ target 'SynthReel' do pod 'collection-view-layouts/TagsLayout' pod 'HWPanModal' pod 'LYEmptyView' + pod 'ZLPhotoBrowser' end diff --git a/SynthReel.xcodeproj/project.pbxproj b/SynthReel.xcodeproj/project.pbxproj index 337bedd..c8545e3 100644 --- a/SynthReel.xcodeproj/project.pbxproj +++ b/SynthReel.xcodeproj/project.pbxproj @@ -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 = ""; }; 3754ACC02ED69105009EBCAD /* SRTopChartsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRTopChartsHeaderView.swift; sourceTree = ""; }; 3754ACC32ED6EDA6009EBCAD /* SREmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SREmpty.swift; sourceTree = ""; }; + 3754ACD02ED81F55009EBCAD /* SRBaseAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRBaseAlert.swift; sourceTree = ""; }; + 3754ACD22ED82113009EBCAD /* SRGradientbutton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRGradientbutton.swift; sourceTree = ""; }; + 3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRDetailRecommendview.swift; sourceTree = ""; }; + 3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRDetailRecommendCell.swift; sourceTree = ""; }; + 3754ACD92ED8374D009EBCAD /* SRPagerViewTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRPagerViewTransformer.swift; sourceTree = ""; }; + 3754ACDB2ED83F80009EBCAD /* SRHomeHistoryBottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRHomeHistoryBottomView.swift; sourceTree = ""; }; + 3754ACE02ED93C4D009EBCAD /* SRCoinPackController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCoinPackController.swift; sourceTree = ""; }; + 3754ACE32ED93E3B009EBCAD /* SRBaseWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRBaseWebViewController.swift; sourceTree = ""; }; + 3754ACE52ED93E7C009EBCAD /* SRWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRWebView.swift; sourceTree = ""; }; + 3754ACE72ED93ED9009EBCAD /* SRWebMessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRWebMessageModel.swift; sourceTree = ""; }; + 3754ACE92ED94065009EBCAD /* SRBaseWebViewController + Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SRBaseWebViewController + Script.swift"; sourceTree = ""; }; + 3754ACEB2ED943AB009EBCAD /* SRAppWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRAppWebViewController.swift; sourceTree = ""; }; + 3754ACED2ED945A1009EBCAD /* Dictionary+SRAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+SRAdd.swift"; sourceTree = ""; }; + 3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRFeedBackController.swift; sourceTree = ""; }; + 3754ACF12ED975B9009EBCAD /* SRRewardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRRewardController.swift; sourceTree = ""; }; 3779D0602ECF1CB8006B1698 /* SRShortHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRShortHeaderView.swift; sourceTree = ""; }; 59DC746604B26E9FF802D317 /* Pods-SynthReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.debug.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.debug.xcconfig"; sourceTree = ""; }; AA88214030574193B51DE563 /* Pods-SynthReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SynthReel.release.xcconfig"; path = "Target Support Files/Pods-SynthReel/Pods-SynthReel.release.xcconfig"; sourceTree = ""; }; @@ -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 = ""; @@ -465,6 +497,8 @@ 03B1A9472ECC6669006C353F /* SRProgressView.swift */, 03B1A9492ECC79AB006C353F /* SREpSelectorView.swift */, 03B1A94D2ECD604B006C353F /* SREpSelectorCell.swift */, + 3754ACD42ED82722009EBCAD /* SRDetailRecommendview.swift */, + 3754ACD62ED82774009EBCAD /* SRDetailRecommendCell.swift */, ); path = V; sourceTree = ""; @@ -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 = ""; @@ -650,6 +689,8 @@ 370D2F1D2ED54C7F00571E77 /* SRHelpCenterController.swift */, 370D2F1F2ED54C8F00571E77 /* SRAboutUsController.swift */, 370D2F212ED54CA400571E77 /* SRPrivacyController.swift */, + 3754ACEF2ED94A4C009EBCAD /* SRFeedBackController.swift */, + 3754ACF12ED975B9009EBCAD /* SRRewardController.swift */, ); path = VC; sourceTree = ""; @@ -682,6 +723,58 @@ path = Empty; sourceTree = ""; }; + 3754ACCF2ED81F2F009EBCAD /* Alert */ = { + isa = PBXGroup; + children = ( + 3754ACD02ED81F55009EBCAD /* SRBaseAlert.swift */, + ); + path = Alert; + sourceTree = ""; + }; + 3754ACD82ED83724009EBCAD /* FSPagerView */ = { + isa = PBXGroup; + children = ( + 3754ACD92ED8374D009EBCAD /* SRPagerViewTransformer.swift */, + ); + path = FSPagerView; + sourceTree = ""; + }; + 3754ACDD2ED93C14009EBCAD /* Coinpack */ = { + isa = PBXGroup; + children = ( + 3754ACDF2ED93C36009EBCAD /* view */, + 3754ACDE2ED93C2A009EBCAD /* VC */, + ); + path = Coinpack; + sourceTree = ""; + }; + 3754ACDE2ED93C2A009EBCAD /* VC */ = { + isa = PBXGroup; + children = ( + 3754ACE02ED93C4D009EBCAD /* SRCoinPackController.swift */, + ); + path = VC; + sourceTree = ""; + }; + 3754ACDF2ED93C36009EBCAD /* view */ = { + isa = PBXGroup; + children = ( + ); + path = view; + sourceTree = ""; + }; + 3754ACE22ED93E04009EBCAD /* webview */ = { + isa = PBXGroup; + children = ( + 3754ACEB2ED943AB009EBCAD /* SRAppWebViewController.swift */, + 3754ACE32ED93E3B009EBCAD /* SRBaseWebViewController.swift */, + 3754ACE92ED94065009EBCAD /* SRBaseWebViewController + Script.swift */, + 3754ACE52ED93E7C009EBCAD /* SRWebView.swift */, + 3754ACE72ED93ED9009EBCAD /* SRWebMessageModel.swift */, + ); + path = webview; + sourceTree = ""; + }; 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; }; diff --git a/SynthReel/Base/API/SRHomeApi.swift b/SynthReel/Base/API/SRHomeApi.swift index 53e1187..3eb8e9b 100644 --- a/SynthReel/Base/API/SRHomeApi.swift +++ b/SynthReel/Base/API/SRHomeApi.swift @@ -118,5 +118,4 @@ struct SRHomeApi { } } } - } diff --git a/SynthReel/Base/API/SRShortApi.swift b/SynthReel/Base/API/SRShortApi.swift index 615e710..1847058 100644 --- a/SynthReel/Base/API/SRShortApi.swift +++ b/SynthReel/Base/API/SRShortApi.swift @@ -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>) 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 = "" diff --git a/SynthReel/Base/Extension/Dictionary+SRAdd.swift b/SynthReel/Base/Extension/Dictionary+SRAdd.swift new file mode 100644 index 0000000..11395f2 --- /dev/null +++ b/SynthReel/Base/Extension/Dictionary+SRAdd.swift @@ -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 + } + +} diff --git a/SynthReel/Base/Extension/String+SRAdd.swift b/SynthReel/Base/Extension/String+SRAdd.swift index 1079396..2ba88f4 100644 --- a/SynthReel/Base/Extension/String+SRAdd.swift +++ b/SynthReel/Base/Extension/String+SRAdd.swift @@ -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) + } + +} diff --git a/SynthReel/Base/Networking/SRUrlPath.swift b/SynthReel/Base/Networking/SRUrlPath.swift index 77084c4..70e773f 100644 --- a/SynthReel/Base/Networking/SRUrlPath.swift +++ b/SynthReel/Base/Networking/SRUrlPath.swift @@ -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 diff --git a/SynthReel/Base/View/SRGradientbutton.swift b/SynthReel/Base/View/SRGradientbutton.swift new file mode 100644 index 0000000..1dcd344 --- /dev/null +++ b/SynthReel/Base/View/SRGradientbutton.swift @@ -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 + } + } + +} diff --git a/SynthReel/Base/webview/SRAppWebViewController.swift b/SynthReel/Base/webview/SRAppWebViewController.swift new file mode 100644 index 0000000..d8b267a --- /dev/null +++ b/SynthReel/Base/webview/SRAppWebViewController.swift @@ -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() + } + } + } + } + + } +} diff --git a/SynthReel/Base/webview/SRBaseWebViewController + Script.swift b/SynthReel/Base/webview/SRBaseWebViewController + Script.swift new file mode 100644 index 0000000..4f6f648 --- /dev/null +++ b/SynthReel/Base/webview/SRBaseWebViewController + Script.swift @@ -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) + } + +} + diff --git a/SynthReel/Base/webview/SRBaseWebViewController.swift b/SynthReel/Base/webview/SRBaseWebViewController.swift new file mode 100644 index 0000000..eab2814 --- /dev/null +++ b/SynthReel/Base/webview/SRBaseWebViewController.swift @@ -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) + } +} diff --git a/SynthReel/Base/webview/SRWebMessageModel.swift b/SynthReel/Base/webview/SRWebMessageModel.swift new file mode 100644 index 0000000..aa9efc6 --- /dev/null +++ b/SynthReel/Base/webview/SRWebMessageModel.swift @@ -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? + +} diff --git a/SynthReel/Base/webview/SRWebView.swift b/SynthReel/Base/webview/SRWebView.swift new file mode 100644 index 0000000..265a58a --- /dev/null +++ b/SynthReel/Base/webview/SRWebView.swift @@ -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) + } + +} diff --git a/SynthReel/Class/Coinpack/VC/SRCoinPackController.swift b/SynthReel/Class/Coinpack/VC/SRCoinPackController.swift new file mode 100644 index 0000000..74a99c0 --- /dev/null +++ b/SynthReel/Class/Coinpack/VC/SRCoinPackController.swift @@ -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. + } + */ + +} diff --git a/SynthReel/Class/Home/V/SRHomeHistoryBottomView.swift b/SynthReel/Class/Home/V/SRHomeHistoryBottomView.swift new file mode 100644 index 0000000..539bc47 --- /dev/null +++ b/SynthReel/Class/Home/V/SRHomeHistoryBottomView.swift @@ -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) + } + + } +} diff --git a/SynthReel/Class/Home/VC/SRHomeViewController.swift b/SynthReel/Class/Home/VC/SRHomeViewController.swift index d9a0c62..40c0d06 100644 --- a/SynthReel/Class/Home/VC/SRHomeViewController.swift +++ b/SynthReel/Class/Home/VC/SRHomeViewController.swift @@ -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 + } + } } diff --git a/SynthReel/Class/Home/VM/SRHomeViewModel.swift b/SynthReel/Class/Home/VM/SRHomeViewModel.swift index a39167e..00307c1 100644 --- a/SynthReel/Class/Home/VM/SRHomeViewModel.swift +++ b/SynthReel/Class/Home/VM/SRHomeViewModel.swift @@ -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 } diff --git a/SynthReel/Class/Player/V/SRDetailRecommendCell.swift b/SynthReel/Class/Player/V/SRDetailRecommendCell.swift new file mode 100644 index 0000000..4fdd924 --- /dev/null +++ b/SynthReel/Class/Player/V/SRDetailRecommendCell.swift @@ -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() + } + +} diff --git a/SynthReel/Class/Player/V/SRDetailRecommendview.swift b/SynthReel/Class/Player/V/SRDetailRecommendview.swift new file mode 100644 index 0000000..31eac76 --- /dev/null +++ b/SynthReel/Class/Player/V/SRDetailRecommendview.swift @@ -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) + } + } + +} diff --git a/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift b/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift index 5acb63d..823bdb8 100644 --- a/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift +++ b/SynthReel/Class/Player/VC/SRDetailPlayerViewController.swift @@ -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 } } } + diff --git a/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift b/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift index ff7c3bd..76df98c 100644 --- a/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift +++ b/SynthReel/Class/Player/VM/SRShortPlayerViewModel.swift @@ -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 + } + + } diff --git a/SynthReel/Class/User/VC/SRFeedBackController.swift b/SynthReel/Class/User/VC/SRFeedBackController.swift new file mode 100644 index 0000000..b74a835 --- /dev/null +++ b/SynthReel/Class/User/VC/SRFeedBackController.swift @@ -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 +// } +// } +// +// } +// +} diff --git a/SynthReel/Class/User/VC/SRRewardController.swift b/SynthReel/Class/User/VC/SRRewardController.swift new file mode 100644 index 0000000..fab1993 --- /dev/null +++ b/SynthReel/Class/User/VC/SRRewardController.swift @@ -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. + } + + + +} diff --git a/SynthReel/Class/User/VC/SRUserViewController.swift b/SynthReel/Class/User/VC/SRUserViewController.swift index 9d4fe2a..0c61d3a 100644 --- a/SynthReel/Class/User/VC/SRUserViewController.swift +++ b/SynthReel/Class/User/VC/SRUserViewController.swift @@ -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")), diff --git a/SynthReel/Class/User/model/SRUserSettingModel.swift b/SynthReel/Class/User/model/SRUserSettingModel.swift index b8df5e3..1f691ea 100644 --- a/SynthReel/Class/User/model/SRUserSettingModel.swift +++ b/SynthReel/Class/User/model/SRUserSettingModel.swift @@ -23,8 +23,8 @@ struct SRUserSettingModel { // case purchaseRecords // ///金币奖励 // case rewardCoins -// case deleteAccount -// case language + case deleteAccount + case language } diff --git a/SynthReel/Libs/Alert/SRBaseAlert.swift b/SynthReel/Libs/Alert/SRBaseAlert.swift new file mode 100644 index 0000000..adb7ef6 --- /dev/null +++ b/SynthReel/Libs/Alert/SRBaseAlert.swift @@ -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 + } + } + } +} + diff --git a/SynthReel/Libs/FSPagerView/SRPagerViewTransformer.swift b/SynthReel/Libs/FSPagerView/SRPagerViewTransformer.swift new file mode 100644 index 0000000..aba3073 --- /dev/null +++ b/SynthReel/Libs/FSPagerView/SRPagerViewTransformer.swift @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Color/#000000.colorset/Contents.json b/SynthReel/Source/Assets.xcassets/Color/#000000.colorset/Contents.json new file mode 100644 index 0000000..7e8f38f --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Color/#000000.colorset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Color/#404040.colorset/Contents.json b/SynthReel/Source/Assets.xcassets/Color/#404040.colorset/Contents.json new file mode 100644 index 0000000..eb2314a --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Color/#404040.colorset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Color/#FF9F4C.colorset/Contents.json b/SynthReel/Source/Assets.xcassets/Color/#FF9F4C.colorset/Contents.json new file mode 100644 index 0000000..c8ea2fe --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Color/#FF9F4C.colorset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/Contents.json new file mode 100644 index 0000000..45dc968 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@2x.png b/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@2x.png new file mode 100644 index 0000000..32f77e4 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@3x.png b/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@3x.png new file mode 100644 index 0000000..01eb044 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/feedList.imageset/feedList@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/Contents.json new file mode 100644 index 0000000..b20dce0 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@2x.png b/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@2x.png new file mode 100644 index 0000000..8929b83 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@3x.png b/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@3x.png new file mode 100644 index 0000000..f200d54 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/recordBottomArrow.imageset/recordBottomArrow@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json new file mode 100644 index 0000000..779b252 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@2x.png b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@2x.png new file mode 100644 index 0000000..17f23c5 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@3x.png b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@3x.png new file mode 100644 index 0000000..3aa0339 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/Image/recordBottomBg.imageset/recordBottomBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@2x.png b/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@2x.png new file mode 100644 index 0000000..e29fd68 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@3x.png b/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@3x.png new file mode 100644 index 0000000..2b7feb9 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Close@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Contents.json new file mode 100644 index 0000000..b9bcce0 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/Close.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/Contents.json new file mode 100644 index 0000000..85a1641 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@2x.png new file mode 100644 index 0000000..73376b9 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@3x.png new file mode 100644 index 0000000..4ff6dfd Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/recommendBg.imageset/recommendBg@3x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/Contents.json b/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/Contents.json new file mode 100644 index 0000000..d3fa0b4 --- /dev/null +++ b/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/Contents.json @@ -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 + } +} diff --git a/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@2x.png b/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@2x.png new file mode 100644 index 0000000..6817494 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@2x.png differ diff --git a/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@3x.png b/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@3x.png new file mode 100644 index 0000000..ee60f71 Binary files /dev/null and b/SynthReel/Source/Assets.xcassets/myShort/suerButtonBg.imageset/suerButtonBg@3x.png differ diff --git a/SynthReel/Source/en.lproj/Localizable.strings b/SynthReel/Source/en.lproj/Localizable.strings index c15df14..2d08dd7 100644 --- a/SynthReel/Source/en.lproj/Localizable.strings +++ b/SynthReel/Source/en.lproj/Localizable.strings @@ -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";