adjust,详情推荐

This commit is contained in:
zjx 2025-06-06 17:50:28 +08:00
parent 46d142cf37
commit a947b20be4
18 changed files with 633 additions and 24 deletions

View File

@ -30,6 +30,7 @@ target 'Veloria' do
pod 'ZFPlayer/AVPlayer' #播放器
pod 'EmptyDataSet-Swift' #空数据页面
pod 'ZLPhotoBrowser' #相册
pod 'Adjust' # Adjust
pod 'FSPagerView' #banner
end

View File

@ -1,7 +1,13 @@
PODS:
- Adjust (5.4.0):
- Adjust/Adjust (= 5.4.0)
- Adjust/Adjust (5.4.0):
- AdjustSignature (= 3.35.2)
- AdjustSignature (3.35.2)
- Alamofire (5.10.2)
- CocoaAsyncSocket (7.6.5)
- EmptyDataSet-Swift (5.0.0)
- FSPagerView (0.8.3)
- HWPanModal (0.9.9)
- Kingfisher (8.3.2)
- KTVHTTPCache (3.0.2):
@ -31,7 +37,9 @@ PODS:
- ZLPhotoBrowser/Core (4.6.0.1)
DEPENDENCIES:
- Adjust
- EmptyDataSet-Swift
- FSPagerView
- HWPanModal
- Kingfisher
- KTVHTTPCache
@ -48,9 +56,12 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- Adjust
- AdjustSignature
- Alamofire
- CocoaAsyncSocket
- EmptyDataSet-Swift
- FSPagerView
- HWPanModal
- Kingfisher
- KTVHTTPCache
@ -66,9 +77,12 @@ SPEC REPOS:
- ZLPhotoBrowser
SPEC CHECKSUMS:
Adjust: a5f881d0cbfe9a6df979b076dc7116fe19ece797
AdjustSignature: 23b9e5d4adcadffc303bb6b410fde617dd88504f
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
EmptyDataSet-Swift: eb382c0c87a2d9c678077385a595cec52da38171
FSPagerView: 670405b2f18e2a87fa37f20b00de783e562c25a8
HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2
Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5
KTVHTTPCache: 5711692cdf9a5ecfe829b1e16577deb3ffe3dc86
@ -83,6 +97,6 @@ SPEC CHECKSUMS:
ZFPlayer: 5cf39e8d9f0c2394a014b0db4767b5b5a6bffe13
ZLPhotoBrowser: 20f32e6429448cc1c008795a1b55472d5772939c
PODFILE CHECKSUM: 4ec05325e0f82746c022a9c8ea6b1af5d1e5092f
PODFILE CHECKSUM: a53439eb21a3498b8f423fddbdb2bfb48f960ebf
COCOAPODS: 1.16.2

View File

@ -213,6 +213,10 @@
BFF5B2662DF16CF60044227A /* VPWaitRestoreModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2652DF16CF60044227A /* VPWaitRestoreModel.swift */; };
BFF5B2682DF16EA30044227A /* VPIAPOrderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2672DF16EA30044227A /* VPIAPOrderModel.swift */; };
BFF5B26A2DF170DD0044227A /* VPIAPVerifyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2692DF170DD0044227A /* VPIAPVerifyModel.swift */; };
BFF5B26C2DF28FD50044227A /* VPStatAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B26B2DF28FD50044227A /* VPStatAPI.swift */; };
BFF5B26E2DF297680044227A /* VPOpenAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B26D2DF297680044227A /* VPOpenAppModel.swift */; };
BFF5B2752DF2C3750044227A /* VPDetailRecommandView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2742DF2C3750044227A /* VPDetailRecommandView.swift */; };
BFF5B2772DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2762DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift */; };
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
/* End PBXBuildFile section */
@ -431,6 +435,10 @@
BFF5B2652DF16CF60044227A /* VPWaitRestoreModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWaitRestoreModel.swift; sourceTree = "<group>"; };
BFF5B2672DF16EA30044227A /* VPIAPOrderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPIAPOrderModel.swift; sourceTree = "<group>"; };
BFF5B2692DF170DD0044227A /* VPIAPVerifyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPIAPVerifyModel.swift; sourceTree = "<group>"; };
BFF5B26B2DF28FD50044227A /* VPStatAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPStatAPI.swift; sourceTree = "<group>"; };
BFF5B26D2DF297680044227A /* VPOpenAppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPOpenAppModel.swift; sourceTree = "<group>"; };
BFF5B2742DF2C3750044227A /* VPDetailRecommandView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDetailRecommandView.swift; sourceTree = "<group>"; };
BFF5B2762DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDetailRecommandBannerCell.swift; sourceTree = "<group>"; };
E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -584,6 +592,7 @@
children = (
1B056E402DDAC30A007EE38D /* VPModel.swift */,
BF0FA70F2DDC6CA200C9E5F2 /* VPListModel.swift */,
BFF5B26D2DF297680044227A /* VPOpenAppModel.swift */,
);
path = Model;
sourceTree = "<group>";
@ -764,6 +773,7 @@
BF0FA73C2DDED2D000C9E5F2 /* VPVideoAPI.swift */,
BF0FA7C22DE45DE300C9E5F2 /* VPUserAPI.swift */,
BFF5B2402DF045BF0044227A /* VPRewardsAPI.swift */,
BFF5B26B2DF28FD50044227A /* VPStatAPI.swift */,
);
path = API;
sourceTree = "<group>";
@ -897,6 +907,8 @@
BFF5AFDD2DEEBF370044227A /* VPPlayerRechargeView.swift */,
BFF5AFDF2DEEC5AA0044227A /* VPPlayerVipBuyView.swift */,
BFF5AFE12DEED2960044227A /* VPPlayerCoinBuyView.swift */,
BFF5B2742DF2C3750044227A /* VPDetailRecommandView.swift */,
BFF5B2762DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift */,
);
path = View;
sourceTree = "<group>";
@ -1335,6 +1347,7 @@
BF5E75B62DE46DB600DE9DFE /* UIScrollView+Empty.swift in Sources */,
1B056E572DDACC6B007EE38D /* VPHomePageViewController.swift in Sources */,
BF0FA7BC2DE4563300C9E5F2 /* VPMeUserInfoCell.swift in Sources */,
BFF5B2772DF2CA4B0044227A /* VPDetailRecommandBannerCell.swift in Sources */,
BF0FA7B82DE44FCC00C9E5F2 /* VPWebViewController.swift in Sources */,
BF0FA72A2DDC922F00C9E5F2 /* VPHomeRecommandCell.swift in Sources */,
BF0FA7322DDEBD6400C9E5F2 /* AppDelegate+Config.swift in Sources */,
@ -1382,6 +1395,7 @@
BF0FA7592DDF1C2800C9E5F2 /* VPPlayerProgressView.swift in Sources */,
BFF5AFE02DEEC5AB0044227A /* VPPlayerVipBuyView.swift in Sources */,
BFF5AFCA2DE97B7A0044227A /* VPWalletViewController.swift in Sources */,
BFF5B26C2DF28FD50044227A /* VPStatAPI.swift in Sources */,
BF0FA71B2DDC7FF200C9E5F2 /* VPImageView.swift in Sources */,
BF0FA7522DDF134700C9E5F2 /* VPVideoPlayerControlView.swift in Sources */,
BF0FA7852DE1561D00C9E5F2 /* VPSearchRecommendedCell.swift in Sources */,
@ -1398,6 +1412,7 @@
BF5E75CD2DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift in Sources */,
BF5E75CE2DE5692D00DE9DFE /* JXPushAnimatedTransition.swift in Sources */,
BF5E75CF2DE5692D00DE9DFE /* UIViewController+JXTransition.swift in Sources */,
BFF5B26E2DF297680044227A /* VPOpenAppModel.swift in Sources */,
BFF5B23F2DF0443B0044227A /* VPWebScriptModel.swift in Sources */,
BFF5B23B2DF018900044227A /* VPAlertView.swift in Sources */,
BF5E75D02DE5692D00DE9DFE /* UIGestureRecognizer+JXTransition.swift in Sources */,
@ -1493,6 +1508,7 @@
BFF5AFCC2DE98C7F0044227A /* VPOrderRecordsViewController.swift in Sources */,
1B056E412DDAC30A007EE38D /* VPModel.swift in Sources */,
BF0FA70A2DDC69C800C9E5F2 /* VPTableViewCell.swift in Sources */,
BFF5B2752DF2C3750044227A /* VPDetailRecommandView.swift in Sources */,
BF0FA7A12DE1AA5100C9E5F2 /* VPTableView.swift in Sources */,
1B056E442DDAC355007EE38D /* UIDevice+VPAdd.swift in Sources */,
BF0FA7632DE006E700C9E5F2 /* VPDetailPlayerCell.swift in Sources */,

View File

@ -16,13 +16,73 @@ extension SceneDelegate {
}
//facebook
ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation])
var result = ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation])
if !result {
vp_handleOpenAppMessage(webpageURL: url)
}
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let webpageURL = userActivity.webpageURL else { return }
vp_handleOpenAppMessage(webpageURL: webpageURL)
}
}
extension SceneDelegate {
static var hasOpenMessage = false
func vp_handleOpenAppMessage(webpageURL: URL?) {
guard VPNetworkReachabilityManager.manager.isReachable == true else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self._handleOpenAppMessage(webpageURL: webpageURL)
}
}
private func _handleOpenAppMessage(webpageURL: URL?) {
if Self.hasOpenMessage { return }
Self.hasOpenMessage = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
Self.hasOpenMessage = false
}
//URL
var statUrlStr: String? = webpageURL?.absoluteString
var data: [String : Any]? = webpageURL?.query?.vp_urlQuryToDictionary()
if let pasteStr = UIPasteboard.general.string {
UIPasteboard.general.string = nil
let tempArr = pasteStr.components(separatedBy: "?")
let query = tempArr.last
let tempData = query?.vp_urlQuryToDictionary()
if tempData?["short_play_id"] != nil {
data = tempData
statUrlStr = pasteStr
}
}
if let urlStr = statUrlStr {//
VPStatAPI.requestStatW2a(data: urlStr)
}
guard let data = data else { return }
guard let model = VPOpenAppModel.deserialize(from: data) else { return }
guard let shortPlayId = model.short_play_id, shortPlayId.count > 0 else { return }
let vc = VPDetailPlayerViewController()
vc.shortPlayId = shortPlayId
VPAppTool.topViewController?.navigationController?.pushViewController(vc, animated: true)
}

View File

@ -7,6 +7,7 @@
import UIKit
import FacebookCore
import AdjustSdk
extension AppDelegate {
@ -14,7 +15,11 @@ extension AppDelegate {
//facebook
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
///
//
MJRefreshConfig.default.languageCode = VPLocalizedManager.shared.mjLocalizedKey
//Adjust
let config = ADJConfig(appToken: "jmtc740fki68", environment: ADJEnvironmentProduction)
Adjust.initSdk(config)
}
}

View File

@ -12,44 +12,55 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
private var timer: Timer?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
VPAppTool.windowScene = windowScene
timer = Timer.scheduledTimer(timeInterval: 60 * 10, target: YYWeakProxy(target: self), selector: #selector(handleOnLine), userInfo: nil, repeats: true)
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: VPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
window = UIWindow(windowScene: windowScene)
window?.rootViewController = VPTabBarController()
window?.makeKeyAndVisible()
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
VPStatAPI.requestEnterApp()
vp_handleOpenAppMessage(webpageURL: nil)
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
VPStatAPI.requestLeaveApp()
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
extension SceneDelegate {
@objc private func handleOnLine() {
VPStatAPI.requestStatOnLine()
}
@objc private func reachabilityDidChangeNotification() {
vp_handleOpenAppMessage(webpageURL: nil)
}
}

View File

@ -31,3 +31,23 @@ extension String {
return string.size(for: font, size: size, mode: .byWordWrapping)
}
}
extension String {
///url
func vp_urlQuryToDictionary() -> [String : Any] {
let array = self.components(separatedBy: "&")
var tempDic: [String : Any] = [:]
array.forEach {
if let strRange = $0.range(of: "=") {
var key: String = String($0.prefix(upTo: strRange.upperBound))
key.removeLast()
var value: String = String($0.suffix(from: strRange.upperBound))
value = value.removingPercentEncoding ?? value
tempDic[key] = value
}
}
return tempDic
}
}

View File

@ -0,0 +1,25 @@
//
// VPOpenAppModel.swift
// Veloria
//
// Created by on 2025/6/6.
//
import UIKit
import SmartCodable
class VPOpenAppModel: VPModel, SmartCodable {
enum PathType: String, SmartCaseDefaultable {
case videoDetail = "detail"
///
case feedback = "feedback"
///
case promotion = "promotion"
}
var id: String?
var message_id: String?
var short_play_id: String?
var path: PathType?
}

View File

@ -0,0 +1,52 @@
//
// VPStatAPI.swift
// Veloria
//
// Created by on 2025/6/6.
//
import UIKit
class VPStatAPI: NSObject {
///APP
static func requestEnterApp() {
var param = VPNetworkParameters(path: "/customer/enterTheApp")
param.isToast = false
param.isLoding = false
VPNetwork.request(parameters: param) { (_: VPNetworkResponse<String>) in }
}
///APP
static func requestLeaveApp() {
var param = VPNetworkParameters(path: "/customer/leaveApp")
param.isToast = false
param.isLoding = false
VPNetwork.request(parameters: param) { (_: VPNetworkResponse<String>) in }
}
static func requestStatOnLine() {
var param = VPNetworkParameters(path: "/customer/onLine")
param.isToast = false
param.isLoding = false
VPNetwork.request(parameters: param) { (_: VPNetworkResponse<String>) in }
}
///w2a
static func requestStatW2a(data: String) {
var param = VPNetworkParameters(path: "/w2aSelfAttribution")
param.isToast = false
param.isLoding = false
param.parameters = [
"data" : data
]
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<String>) in
}
}
}

View File

@ -139,6 +139,17 @@ class VPVideoAPI: NSObject {
completer?(response.data)
}
}
///
static func requestDetailsRecommand(completer: ((_ list: [VPShortModel]?) -> Void)?) {
var param = VPNetworkParameters(path: "/getDetailsRecommand")
param.method = .get
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPListModel<VPShortModel>>) in
completer?(response.data?.list)
}
}
}
extension VPVideoAPI {

View File

@ -202,7 +202,7 @@ extension VPMeViewController {
]
var cellArr: [VPMeItem] = []
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_05"), title: "Language".localized, type: .language, cellKey: .normal))
// cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_05"), title: "Language".localized, type: .language, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_01"), title: "Privacy Policy".localized, type: .privacyPolicy, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_02"), title: "User Agreement".localized, type: .userAgreement, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_04"), title: "Help Center".localized, type: .feedback, cellKey: .normal))

View File

@ -22,11 +22,14 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController {
private var detailModel: VPVideoDetailModel?
///
private lazy var recommandList: [VPShortModel] = []
//MARK: UI
private lazy var backButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "arrow_left_icon_01"), for: .normal)
button.addTarget(self, action: #selector(handleBack), for: .touchUpInside)
button.addTarget(self, action: #selector(handleBackButton), for: .touchUpInside)
return button
}()
@ -49,8 +52,10 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController {
self.delegate = self
self.dataSource = self
NotificationCenter.default.addObserver(self, selector: #selector(buyVipFinishNotification), name: VPIAPManager.buyVipFinishNotification, object: nil)
self.jx_popDelegate = self
requestDetailData()
requestRecommandDataArr()
vp_setupUI()
vp_addAction()
@ -79,6 +84,28 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController {
VPVideoAPI.requestCreatePlayHistory(videoId: videoInfo.short_play_video_id, shortPlayId: videoInfo.short_play_id)
}
@objc func handleBackButton() {
guard recommandList.count > 0 else {
self.handleBack()
return
}
self.pause()
let view = VPDetailRecommandView()
view.dataArr = recommandList
view.clickCloseButton = { [weak self] in
self?.handleBack()
}
view.clickLookButton = { [weak self] model in
guard let self = self else { return }
self.shortPlayId = model.short_play_id
self.activityId = nil
self.requestDetailData()
}
view.present(in: nil)
}
}
extension VPDetailPlayerViewController {
@ -221,13 +248,22 @@ extension VPDetailPlayerViewController: VPPlayerListViewControllerDelegate {
}
//MARK: -------------- JXViewControllerPopDelegate --------------
extension VPDetailPlayerViewController: JXViewControllerPopDelegate {
func viewControllerPopShouldScrollBegan() -> Bool {
self.handleBackButton()
return false
}
}
extension VPDetailPlayerViewController {
private func requestDetailData() {
guard let shortPlayId = shortPlayId else { return }
VPHUD.show(containerView: self.view)
VPVideoAPI.requestVideoDetail(shortPlayId: shortPlayId, activityId: activityId) { [weak self] model in
VPHUD.dismiss()
guard let self = self else { return }
guard let model = model else { return }
self.detailModel = model
@ -255,4 +291,14 @@ extension VPDetailPlayerViewController {
}
}
private func requestRecommandDataArr() {
VPVideoAPI.requestDetailsRecommand { [weak self] list in
guard let self = self else { return }
if let list = list {
self.recommandList = list
}
}
}
}

View File

@ -0,0 +1,45 @@
//
// VPDetailRecommandBannerCell.swift
// Veloria
//
// Created by on 2025/6/6.
//
import UIKit
import FSPagerView
class VPDetailRecommandBannerCell: FSPagerViewCell {
var model: VPShortModel? {
didSet {
coverImageView.vp_setImage(url: model?.image_url)
}
}
// private lazy var player: VPPlayer = {
//
// }()
private lazy var coverImageView: VPImageView = {
let imageView = VPImageView()
imageView.layer.cornerRadius = 14
imageView.layer.masksToBounds = true
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(coverImageView)
coverImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
@MainActor required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -0,0 +1,287 @@
//
// VPDetailRecommandView.swift
// Veloria
//
// Created by on 2025/6/6.
//
import UIKit
import FSPagerView
class VPDetailRecommandView: HWPanModalContentView {
var dataArr: [VPShortModel] = [] {
didSet {
CATransaction.setCompletionBlock { [weak self] in
self?.setVideoTitle()
}
CATransaction.begin()
bannerView.reloadData()
CATransaction.commit()
}
}
var clickCloseButton: (() -> Void)?
var clickLookButton: ((_ model: VPShortModel) -> Void)?
//MARK: UI
private lazy var bgView: UIView = {
let view = VPGradientView()
view.locations = [0, 0.5, 1]
view.colors = [UIColor.color045241().cgColor, UIColor.color000000().cgColor, UIColor.color000000().cgColor]
view.startPoint = .init(x: 0, y: 0)
view.endPoint = .init(x: 1, y: 1)
return view
}()
private lazy var closeButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "close_icon_01"), for: .normal)
button.addTarget(self, action: #selector(handleCloseButton), for: .touchUpInside)
return button
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 16)
label.textColor = .colorFFFFFF()
label.text = "kDetailRecommandTitle".localized
return label
}()
private lazy var bannerView: FSPagerView = {
let view = FSPagerView()
view.transformer = FSPagerViewTransformer(type: .overlap)
view.transformer?.minimumScale = 0.8
view.decelerationDistance = FSPagerView.automaticDistance
view.itemSize = .init(width: 194, height: 258)
view.isInfinite = true
view.delegate = self
view.dataSource = self
view.register(VPDetailRecommandBannerCell.self, forCellWithReuseIdentifier: "cell")
return view
}()
private lazy var videoTitleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorFFFFFF()
label.textAlignment = .center
return label
}()
private lazy var videoCategoryView: UIButton = {
var config = UIButton.Configuration.plain()
config.contentInsets = .init(top: 0, leading: 5, bottom: 0, trailing: 5)
let view = UIButton(configuration: config)
view.isUserInteractionEnabled = false
view.backgroundColor = .colorFFFFFF(alpha: 0.1)
view.layer.cornerRadius = 3
view.layer.masksToBounds = true
view.configurationUpdateHandler = { [weak self] button in
guard let self = self else { return }
if self.dataArr.count <= self.bannerView.currentIndex { return }
let model = self.dataArr[self.bannerView.currentIndex]
let category = model.category?.last ?? ""
let string = AttributedString.createAttributedString(string: category, color: .colorAFAFAF(), font: .fontRegular(ofSize: 10))
button.configuration?.attributedTitle = string
}
return view
}()
private lazy var lookButton: UIButton = {
let button = VPGradientButton(type: .custom)
button.locations = [0, 1]
button.colors = [UIColor.color05CEA0(alpha: 0.3).cgColor, UIColor.color7C174F(alpha: 0.3).cgColor]
button.startPoint = .init(x: 0, y: 0.3)
button.endPoint = .init(x: 1, y: 0.8)
button.bt_setGradientBorder()
button.setTitle("Watch Now".localized, for: .normal)
button.setTitleColor(.colorFFFFFF(), for: .normal)
button.titleLabel?.font = .fontMedium(ofSize: 14)
button.layer.cornerRadius = 24
button.layer.masksToBounds = true
button.addTarget(self, action: #selector(handleLookButton), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
vp_setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
}
//MARK: HWPanModalPresentable
override func longFormHeight() -> PanModalHeight {
return PanModalHeightMake(.content, 473 + UIScreen.tabbarSafeBottomMargin)
}
override func showDragIndicator() -> Bool {
return false
}
override func backgroundConfig() -> HWBackgroundConfig {
let config = HWBackgroundConfig()
config.backgroundAlpha = 0.6
return config
}
override func cornerRadius() -> CGFloat {
return 24
}
override func allowsTapBackgroundToDismiss() -> Bool {
return false
}
override func allowsDragToDismiss() -> Bool {
return false
}
override func minVerticalVelocityToTriggerDismiss() -> CGFloat {
return 0
}
override func allowsPullDownWhenShortState() -> Bool {
return false
}
}
extension VPDetailRecommandView {
private func setVideoTitle() {
let index = self.bannerView.currentIndex
let cell = self.bannerView.cellForItem(at: index)
vpLog(message: cell)
let model = self.dataArr[index]
videoTitleLabel.text = model.name
if let category = model.category?.last, !category.isEmpty {
videoCategoryView.isHidden = false
videoCategoryView.setNeedsUpdateConfiguration()
} else {
videoCategoryView.isHidden = true
}
}
@objc private func handleCloseButton() {
self.clickCloseButton?()
self.dismiss(animated: true) {
}
}
@objc private func handleLookButton() {
let index = self.bannerView.currentIndex
self.clickLookButton?(dataArr[index])
self.dismiss(animated: true) { }
}
}
extension VPDetailRecommandView {
private func vp_setupUI() {
addSubview(bgView)
addSubview(titleLabel)
addSubview(closeButton)
addSubview(bannerView)
addSubview(videoTitleLabel)
addSubview(videoCategoryView)
addSubview(lookButton)
bgView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
titleLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(39)
}
closeButton.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-5)
make.top.equalToSuperview().offset(5)
make.width.height.equalTo(40)
}
bannerView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalToSuperview().offset(77)
make.height.equalTo(260)
}
videoTitleLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(bannerView.snp.bottom).offset(9)
make.width.equalTo(200)
}
videoCategoryView.snp.makeConstraints { make in
// make.left.equalTo(videoTitleLabel)
make.centerX.equalToSuperview()
make.top.equalTo(bannerView.snp.bottom).offset(38)
make.height.equalTo(16)
}
lookButton.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.equalTo(240)
make.height.equalTo(48)
make.top.equalTo(bannerView.snp.bottom).offset(74)
}
}
}
//MARK: -------------- FSPagerViewDelegate FSPagerViewDataSource --------------
extension VPDetailRecommandView: FSPagerViewDelegate, FSPagerViewDataSource {
func numberOfItems(in pagerView: FSPagerView) -> Int {
return dataArr.count
}
func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
let cell = pagerView.dequeueReusableCell(withReuseIdentifier: "cell", at: index) as! VPDetailRecommandBannerCell
cell.model = self.dataArr[index]
return cell
}
func pagerViewDidEndDecelerating(_ pagerView: FSPagerView) {
setVideoTitle()
}
}

View File

@ -14,6 +14,14 @@
<string>fb642299232204955</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>VeloriaTV</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>642299232204955</string>

View File

@ -86,7 +86,9 @@
"Expired" = "Expired";
"Success" = "Success";
"Restore" = "Restore";
"Watch Now" = "Watch Now";
"kDetailRecommandTitle" = "Picked Just for You";
"kHomeTitleText" = "10,000+ addictive shorts await!";
"kSearchPlaceholderText1" = "Search dramas";
"kSearchPlaceholderText2" = "#Recersal of fate";

View File

@ -6,6 +6,10 @@
<array>
<string>Default</string>
</array>
<key>com.apple.developer.associated-domains</key>
<array>
<string>webcredentials:example.com</string>
</array>
<key>keychain-access-groups</key>
<array/>
</dict>

View File

@ -15,3 +15,5 @@ D-U-N-S 616751820
沙盒账号
veloria@test.com
Test@168
veloria1@test.com
Discover2024