视频加锁UI,视频页面支付UI
@ -171,6 +171,13 @@
|
||||
BFF5AFD42DE9A5FB0044227A /* VPVIPRecordCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFD32DE9A5FB0044227A /* VPVIPRecordCell.swift */; };
|
||||
BFF5AFD62DE9A8D70044227A /* VPWalletHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFD52DE9A8D70044227A /* VPWalletHeaderView.swift */; };
|
||||
BFF5AFD82DE9B8010044227A /* VPWalletHeaderItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFD72DE9B8010044227A /* VPWalletHeaderItemView.swift */; };
|
||||
BFF5AFDA2DEE90350044227A /* VPVideoLockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFD92DEE90350044227A /* VPVideoLockView.swift */; };
|
||||
BFF5AFDC2DEEA09F0044227A /* VPVideoUnlockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFDB2DEEA09F0044227A /* VPVideoUnlockModel.swift */; };
|
||||
BFF5AFDE2DEEBF370044227A /* VPPlayerRechargeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFDD2DEEBF370044227A /* VPPlayerRechargeView.swift */; };
|
||||
BFF5AFE02DEEC5AB0044227A /* VPPlayerVipBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFDF2DEEC5AA0044227A /* VPPlayerVipBuyView.swift */; };
|
||||
BFF5AFE22DEED2960044227A /* VPPlayerCoinBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFE12DEED2960044227A /* VPPlayerCoinBuyView.swift */; };
|
||||
BFF5AFE62DEEDB7F0044227A /* VPRewardsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFE52DEEDB7F0044227A /* VPRewardsViewController.swift */; };
|
||||
BFF5B21C2DEEDE130044227A /* VPWebViewController+Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B21B2DEEDE130044227A /* VPWebViewController+Script.swift */; };
|
||||
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -348,6 +355,13 @@
|
||||
BFF5AFD32DE9A5FB0044227A /* VPVIPRecordCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPVIPRecordCell.swift; sourceTree = "<group>"; };
|
||||
BFF5AFD52DE9A8D70044227A /* VPWalletHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWalletHeaderView.swift; sourceTree = "<group>"; };
|
||||
BFF5AFD72DE9B8010044227A /* VPWalletHeaderItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWalletHeaderItemView.swift; sourceTree = "<group>"; };
|
||||
BFF5AFD92DEE90350044227A /* VPVideoLockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPVideoLockView.swift; sourceTree = "<group>"; };
|
||||
BFF5AFDB2DEEA09F0044227A /* VPVideoUnlockModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPVideoUnlockModel.swift; sourceTree = "<group>"; };
|
||||
BFF5AFDD2DEEBF370044227A /* VPPlayerRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPPlayerRechargeView.swift; sourceTree = "<group>"; };
|
||||
BFF5AFDF2DEEC5AA0044227A /* VPPlayerVipBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPPlayerVipBuyView.swift; sourceTree = "<group>"; };
|
||||
BFF5AFE12DEED2960044227A /* VPPlayerCoinBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPPlayerCoinBuyView.swift; sourceTree = "<group>"; };
|
||||
BFF5AFE52DEEDB7F0044227A /* VPRewardsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPRewardsViewController.swift; sourceTree = "<group>"; };
|
||||
BFF5B21B2DEEDE130044227A /* VPWebViewController+Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VPWebViewController+Script.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 */
|
||||
|
||||
@ -435,6 +449,7 @@
|
||||
1B056E362DDAC1E8007EE38D /* Class */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BFF5AFE32DEED86B0044227A /* Rewards */,
|
||||
BFF5AFBB2DE837710044227A /* Wallet */,
|
||||
BF0FA7A62DE4437F00C9E5F2 /* Me */,
|
||||
BF0FA7952DE1948A00C9E5F2 /* MyList */,
|
||||
@ -698,6 +713,7 @@
|
||||
BF0FA7012DDC667C00C9E5F2 /* VPVideoInfoModel.swift */,
|
||||
BF0FA7602DDFFE7100C9E5F2 /* VPVideoDetailModel.swift */,
|
||||
BF0FA7702DE062EB00C9E5F2 /* VPVideoRateModel.swift */,
|
||||
BFF5AFDB2DEEA09F0044227A /* VPVideoUnlockModel.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@ -794,6 +810,10 @@
|
||||
BF0FA76A2DE0533400C9E5F2 /* VPEpisodeMenuView.swift */,
|
||||
BF0FA76E2DE062A700C9E5F2 /* VPRateSelectedView.swift */,
|
||||
BF0FA7722DE0671200C9E5F2 /* VPRateSelectedCell.swift */,
|
||||
BFF5AFD92DEE90350044227A /* VPVideoLockView.swift */,
|
||||
BFF5AFDD2DEEBF370044227A /* VPPlayerRechargeView.swift */,
|
||||
BFF5AFDF2DEEC5AA0044227A /* VPPlayerVipBuyView.swift */,
|
||||
BFF5AFE12DEED2960044227A /* VPPlayerCoinBuyView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -890,7 +910,6 @@
|
||||
children = (
|
||||
BF0FA7AE2DE443E000C9E5F2 /* VPMeViewController.swift */,
|
||||
BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */,
|
||||
BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */,
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
@ -924,6 +943,8 @@
|
||||
children = (
|
||||
BF0FA7B52DE44E8000C9E5F2 /* VPWebView.swift */,
|
||||
BF0FA7B72DE44FCC00C9E5F2 /* VPWebViewController.swift */,
|
||||
BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */,
|
||||
BFF5B21B2DEEDE130044227A /* VPWebViewController+Script.swift */,
|
||||
);
|
||||
path = WebView;
|
||||
sourceTree = "<group>";
|
||||
@ -1015,6 +1036,22 @@
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BFF5AFE32DEED86B0044227A /* Rewards */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BFF5AFE42DEED8800044227A /* Controller */,
|
||||
);
|
||||
path = Rewards;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BFF5AFE42DEED8800044227A /* Controller */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BFF5AFE52DEEDB7F0044227A /* VPRewardsViewController.swift */,
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -1180,6 +1217,7 @@
|
||||
BF0FA73B2DDED1C700C9E5F2 /* VPHomeListCell.swift in Sources */,
|
||||
BF0FA79F2DE1A29A00C9E5F2 /* VPCollectListCell.swift in Sources */,
|
||||
BF0FA7592DDF1C2800C9E5F2 /* VPPlayerProgressView.swift in Sources */,
|
||||
BFF5AFE02DEEC5AB0044227A /* VPPlayerVipBuyView.swift in Sources */,
|
||||
BFF5AFCA2DE97B7A0044227A /* VPWalletViewController.swift in Sources */,
|
||||
BF0FA71B2DDC7FF200C9E5F2 /* VPImageView.swift in Sources */,
|
||||
BF0FA7522DDF134700C9E5F2 /* VPVideoPlayerControlView.swift in Sources */,
|
||||
@ -1190,6 +1228,7 @@
|
||||
BFF5AFA42DE6F15E0044227A /* VPMeVipCell.swift in Sources */,
|
||||
BFF5AFB02DE7F9A80044227A /* VPVipViewController.swift in Sources */,
|
||||
BF0FA75D2DDF208400C9E5F2 /* VPExplorePlayerControlView.swift in Sources */,
|
||||
BFF5B21C2DEEDE130044227A /* VPWebViewController+Script.swift in Sources */,
|
||||
BF5E75CB2DE5692D00DE9DFE /* UINavigationController+JXTransition.swift in Sources */,
|
||||
BF5E75CC2DE5692D00DE9DFE /* JXTransitionDefine.swift in Sources */,
|
||||
BF5E75CD2DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift in Sources */,
|
||||
@ -1201,6 +1240,7 @@
|
||||
BF5E75D22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift in Sources */,
|
||||
BF5E75D32DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift in Sources */,
|
||||
1B056E462DDAC370007EE38D /* UIScreen+VPAdd.swift in Sources */,
|
||||
BFF5AFDE2DEEBF370044227A /* VPPlayerRechargeView.swift in Sources */,
|
||||
BFF5AFAA2DE7070A0044227A /* VPMeCoinItemView.swift in Sources */,
|
||||
BF0FA7692DE0502900C9E5F2 /* VPEpisodeCell.swift in Sources */,
|
||||
BF5E75BE2DE54B2800DE9DFE /* VPAboutUsHeaderView.swift in Sources */,
|
||||
@ -1223,6 +1263,7 @@
|
||||
BFF5AFCE2DE99C730044227A /* VPCoinRecordViewController.swift in Sources */,
|
||||
BF0FA7732DE0671200C9E5F2 /* VPRateSelectedCell.swift in Sources */,
|
||||
1B056E4D2DDAC7C1007EE38D /* VPTabBarController.swift in Sources */,
|
||||
BFF5AFDC2DEEA09F0044227A /* VPVideoUnlockModel.swift in Sources */,
|
||||
BF5E75C02DE5566200DE9DFE /* VPHomePageControlView.swift in Sources */,
|
||||
BFF5AFC22DE837FC0044227A /* VPPayTemplateItem.swift in Sources */,
|
||||
BF0FA6DA2DDC5CB600C9E5F2 /* VPLoginManager.swift in Sources */,
|
||||
@ -1239,6 +1280,7 @@
|
||||
1B056E3F2DDAC2DB007EE38D /* VPCryptorService.swift in Sources */,
|
||||
BF0FA7202DDC83AE00C9E5F2 /* JXButton.swift in Sources */,
|
||||
BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */,
|
||||
BFF5AFE22DEED2960044227A /* VPPlayerCoinBuyView.swift in Sources */,
|
||||
BF0FA7992DE1951A00C9E5F2 /* VPMyListViewController.swift in Sources */,
|
||||
BF0FA7452DDF027900C9E5F2 /* VPPlayer.swift in Sources */,
|
||||
BFF5AFC62DE863C00044227A /* VPGradientButton.swift in Sources */,
|
||||
@ -1280,6 +1322,7 @@
|
||||
BF0FA7172DDC78FF00C9E5F2 /* ZKCycleScrollView.swift in Sources */,
|
||||
BF0FA7612DDFFE7100C9E5F2 /* VPVideoDetailModel.swift in Sources */,
|
||||
BFF5AFD22DE9A58A0044227A /* VPVIPRecordViewController.swift in Sources */,
|
||||
BFF5AFDA2DEE90350044227A /* VPVideoLockView.swift in Sources */,
|
||||
BF5E75B82DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift in Sources */,
|
||||
BF0FA6D52DDC5B5D00C9E5F2 /* VPApi.swift in Sources */,
|
||||
BF0FA7C12DE45D5D00C9E5F2 /* VPUserInfo.swift in Sources */,
|
||||
@ -1289,6 +1332,7 @@
|
||||
BFF5AFC02DE837D60044227A /* VPPayTemplateModel.swift in Sources */,
|
||||
BF0FA7B62DE44E8000C9E5F2 /* VPWebView.swift in Sources */,
|
||||
1B056E492DDAC3DF007EE38D /* VPAppTool.swift in Sources */,
|
||||
BFF5AFE62DEEDB7F0044227A /* VPRewardsViewController.swift in Sources */,
|
||||
BF0FA74E2DDF067E00C9E5F2 /* VPVideoPlayViewModel.swift in Sources */,
|
||||
BF0FA75B2DDF206000C9E5F2 /* VPExplorePlayerCell.swift in Sources */,
|
||||
BF0FA7412DDEFBC700C9E5F2 /* UIScrollView+VPRefresh.swift in Sources */,
|
||||
|
@ -154,4 +154,22 @@ extension VPTabBarController {
|
||||
viewController?.showHistoryPage()
|
||||
}
|
||||
}
|
||||
|
||||
func openCollectPage() {
|
||||
|
||||
var index: Int?
|
||||
var viewController: VPMyListViewController?
|
||||
self.viewControllers?.enumerated().forEach({
|
||||
guard let nav = $1 as? UINavigationController else { return }
|
||||
if let vc = nav.viewControllers.first as? VPMyListViewController {
|
||||
index = $0
|
||||
viewController = vc
|
||||
}
|
||||
|
||||
})
|
||||
if let index = index {
|
||||
self.selectedIndex = index
|
||||
viewController?.showCollectPage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import UIKit
|
||||
extension UIDevice {
|
||||
|
||||
//http://theiphonewiki.com/wiki/Models
|
||||
static func sp_machineModelName() -> String {
|
||||
static func vp_machineModelName() -> String {
|
||||
guard let machineModel = UIDevice.current.machineModel else { return "" }
|
||||
let map = [
|
||||
"iPhone1,1" : "iPhone",
|
||||
|
@ -23,4 +23,19 @@ class VPWalletAPI {
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
///金币解锁视频
|
||||
static func requestCoinUnlockVideo(shortPlayId: String, videoId: String, completer: ((_ model: VPVideoUnlockModel?) -> Void)?) {
|
||||
|
||||
var param = VPNetworkParameters(path: "/buy_video")
|
||||
param.isLoding = true
|
||||
param.parameters = [
|
||||
"short_play_id" : shortPlayId,
|
||||
"video_id" : videoId,
|
||||
]
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPVideoUnlockModel>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ extension VPApi: TargetType {
|
||||
"app-name" : "",
|
||||
"system-type" : "ios",
|
||||
"idfa" : JXUUID.idfa(),
|
||||
"model" : UIDevice.sp_machineModelName(),
|
||||
"model" : UIDevice.vp_machineModelName(),
|
||||
// "security" : "false",
|
||||
]
|
||||
//登录信息
|
||||
|
@ -11,8 +11,9 @@ class VPCampaignWebViewController: VPWebViewController {
|
||||
|
||||
var id: String?
|
||||
|
||||
///重试次数
|
||||
private var receiveDataCount = 0
|
||||
|
||||
var theme: String? = "theme_1"
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
@ -60,8 +61,12 @@ extension VPCampaignWebViewController {
|
||||
"time_zone" : String.timeZone(),
|
||||
"lang" : VPLocalizedManager.shared.currentLocalizedKey,
|
||||
"type" : "ios",
|
||||
"theme" : "theme_1",
|
||||
]
|
||||
|
||||
if let theme = theme {
|
||||
dic["theme"] = theme
|
||||
}
|
||||
|
||||
if let id = id {
|
||||
dic["id"] = id
|
||||
}
|
@ -33,16 +33,15 @@ class VPWebView: WKWebView {
|
||||
|
||||
weak var delegate: VPWebViewDelegate?
|
||||
|
||||
// private(set) var scriptMessageHandlerArray: [SPWebViewMessageName] = [
|
||||
// WebMessageAPP,
|
||||
// WebMessageOpenFeedbackList,
|
||||
// WebMessageOpenFeedbackDetail,
|
||||
// WebMessageOpenPhotoPicker,
|
||||
// ]
|
||||
private(set) var scriptMessageHandlerArray: [VPWebViewMessageName] = [
|
||||
VPWebMessageAPP,
|
||||
VPWebMessageOpenFeedbackList,
|
||||
VPWebMessageOpenFeedbackDetail,
|
||||
VPWebMessageOpenPhotoPicker,
|
||||
]
|
||||
|
||||
|
||||
deinit {
|
||||
|
||||
self.removeObserver(self, forKeyPath: "estimatedProgress")
|
||||
self.removeObserver(self, forKeyPath: "title")
|
||||
|
||||
@ -50,7 +49,7 @@ class VPWebView: WKWebView {
|
||||
|
||||
override init(frame: CGRect, configuration: WKWebViewConfiguration) {
|
||||
super.init(frame: frame, configuration: configuration)
|
||||
// addScriptMessageHandler()
|
||||
addScriptMessageHandler()
|
||||
_setupInit()
|
||||
}
|
||||
required init?(coder: NSCoder) {
|
||||
@ -78,20 +77,20 @@ class VPWebView: WKWebView {
|
||||
|
||||
func load(urlStr: String) {
|
||||
guard let url = URL(string: urlStr) else { return }
|
||||
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30)
|
||||
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30)
|
||||
self.load(request)
|
||||
}
|
||||
|
||||
// func removeScriptMessageHandler() {
|
||||
// self.scriptMessageHandlerArray.forEach{
|
||||
// configuration.userContentController.removeScriptMessageHandler(forName: $0)
|
||||
// }
|
||||
// }
|
||||
// func addScriptMessageHandler() {
|
||||
// self.scriptMessageHandlerArray.forEach{
|
||||
// configuration.userContentController.add(YYWeakProxy(target: self) as! WKScriptMessageHandler, name: $0)
|
||||
// }
|
||||
// }
|
||||
func removeScriptMessageHandler() {
|
||||
self.scriptMessageHandlerArray.forEach{
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: $0)
|
||||
}
|
||||
}
|
||||
func addScriptMessageHandler() {
|
||||
self.scriptMessageHandlerArray.forEach{
|
||||
configuration.userContentController.add(YYWeakProxy(target: self) as! WKScriptMessageHandler, name: $0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
32
Veloria/Base/WebView/VPWebViewController+Script.swift
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// VPWebViewController+Script.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/6/3.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import WebKit
|
||||
|
||||
typealias VPWebViewMessageName = String
|
||||
|
||||
///APP交互
|
||||
let VPWebMessageAPP: VPWebViewMessageName = "js2app"
|
||||
///打开反馈列表
|
||||
let VPWebMessageOpenFeedbackList: VPWebViewMessageName = "openFeedbackList"
|
||||
///打开反馈详情
|
||||
let VPWebMessageOpenFeedbackDetail: VPWebViewMessageName = "openFeedbackDetail"
|
||||
///打开相册
|
||||
let VPWebMessageOpenPhotoPicker: VPWebViewMessageName = "openPhotoPicker"
|
||||
|
||||
extension VPWebViewController {
|
||||
|
||||
func vp_webViewUserContentController(didReceive message: WKScriptMessage) {
|
||||
let name = message.name
|
||||
let body = message.body
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -98,6 +98,6 @@ extension VPWebViewController: VPWebViewDelegate {
|
||||
}
|
||||
|
||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
// _webViewUserContentController(didReceive: message)
|
||||
vp_webViewUserContentController(didReceive: message)
|
||||
}
|
||||
}
|
||||
|
@ -32,11 +32,13 @@ class VPMeToolCell: VPTableViewCell {
|
||||
|
||||
private lazy var rewardsButton: UIButton = {
|
||||
let button = self.createButton(icon: UIImage(named: "rewards_icon_01"), title: "Rewards".localized)
|
||||
button.addTarget(self, action: #selector(handleRewardsButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var favoritesButton: UIButton = {
|
||||
let button = self.createButton(icon: UIImage(named: "favorites_icon_01"), title: "Favorites".localized)
|
||||
button.addTarget(self, action: #selector(handleFavoritesButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
@ -76,6 +78,16 @@ extension VPMeToolCell {
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
@objc private func handleRewardsButton() {
|
||||
let vc = VPRewardsViewController()
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
@objc private func handleFavoritesButton() {
|
||||
let tabbarVC = VPAppTool.rootViewController as? VPTabBarController
|
||||
tabbarVC?.openCollectPage()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPMeToolCell {
|
||||
|
@ -138,6 +138,12 @@ class VPMyListViewController: VPViewController {
|
||||
self?.pageView.selectMenu(with: 1)
|
||||
}
|
||||
}
|
||||
|
||||
func showCollectPage() {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
|
||||
self?.pageView.selectMenu(with: 0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,15 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController {
|
||||
|
||||
override func play() {
|
||||
guard let videoInfo = self.viewModel.currentPlayer?.videoInfo else { return }
|
||||
super.play()
|
||||
if videoInfo.is_lock == true {
|
||||
self.pause()
|
||||
|
||||
self.onRecharge()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
super.play()
|
||||
VPVideoAPI.requestCreatePlayHistory(videoId: videoInfo.short_play_video_id, shortPlayId: videoInfo.short_play_id)
|
||||
}
|
||||
|
||||
@ -92,6 +99,9 @@ extension VPDetailPlayerViewController {
|
||||
self?.onEpisode()
|
||||
}
|
||||
|
||||
self.viewModel.handleUnlock = { [weak self] in
|
||||
self?.unlockVideo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,6 +119,50 @@ extension VPDetailPlayerViewController {
|
||||
self.episodeView = view
|
||||
}
|
||||
|
||||
private func unlockVideo() {
|
||||
guard let videoInfo = self.viewModel.currentPlayer?.videoInfo else { return }
|
||||
|
||||
guard let sId = videoInfo.short_play_id, let vId = videoInfo.short_play_video_id else { return }
|
||||
|
||||
VPWalletAPI.requestCoinUnlockVideo(shortPlayId: sId, videoId: vId) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else { return }
|
||||
|
||||
switch model.status {
|
||||
case .jump:
|
||||
VPToast.show(text: "kLockPreviousEpisodeText".localized)
|
||||
|
||||
case .noPlay:
|
||||
VPToast.show(text: "kLockFailText".localized)
|
||||
|
||||
case .notEnough:
|
||||
self.onRecharge()
|
||||
break
|
||||
|
||||
case .success:
|
||||
videoInfo.is_lock = false
|
||||
self.reloadData { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.play()
|
||||
}
|
||||
|
||||
VPLoginManager.manager.updateUserInfo(completer: nil)
|
||||
|
||||
default: break
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///打开充值页面
|
||||
private func onRecharge() {
|
||||
let view = VPPlayerRechargeView()
|
||||
view.present(in: nil)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- VPPlayerListViewControllerDataSource --------------
|
||||
|
25
Veloria/Class/Player/Model/VPVideoUnlockModel.swift
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// VPVideoUnlockModel.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/6/3.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class VPVideoUnlockModel: VPModel, SmartCodable {
|
||||
|
||||
enum ResponseStatus: String, SmartCaseDefaultable {
|
||||
///前面还有没购买的剧
|
||||
case jump = "jump"
|
||||
///没找到视频
|
||||
case noPlay = "no_play"
|
||||
///金币不足跳充值
|
||||
case notEnough = "not_enough"
|
||||
///购买成功
|
||||
case success = "success"
|
||||
}
|
||||
|
||||
var status: ResponseStatus?
|
||||
}
|
@ -21,6 +21,8 @@ class VPDetailPlayerControlView: VPVideoPlayerControlView {
|
||||
override var videoInfo: VPVideoInfoModel? {
|
||||
didSet {
|
||||
epView.setTitle(String(format: "EP.%@".localized, "\(videoInfo?.episode ?? "0")"), for: .normal)
|
||||
lockView.isHidden = !(videoInfo?.is_lock ?? false)
|
||||
lockView.videoInfo = videoInfo
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,6 +115,15 @@ class VPDetailPlayerControlView: VPVideoPlayerControlView {
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var lockView: VPVideoLockView = {
|
||||
let view = VPVideoLockView()
|
||||
view.clickUnlockButton = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.viewModel?.handleUnlock?()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
deinit {
|
||||
self.viewModel?.removeObserver(self, forKeyPath: "rateModel")
|
||||
}
|
||||
@ -172,6 +183,7 @@ extension VPDetailPlayerControlView {
|
||||
epBgView.addSubview(allEpView)
|
||||
addSubview(rateButton)
|
||||
addSubview(timeLabel)
|
||||
addSubview(lockView)
|
||||
|
||||
self.sendSubviewToBack(self.bottomView)
|
||||
|
||||
@ -216,6 +228,10 @@ extension VPDetailPlayerControlView {
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.bottom.equalTo(epBgView.snp.top).offset(-16)
|
||||
}
|
||||
|
||||
lockView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,22 +13,25 @@ class VPEpisodeCell: VPCollectionViewCell {
|
||||
var videoInfoModel: VPVideoInfoModel? {
|
||||
didSet {
|
||||
numLabel.text = videoInfoModel?.episode
|
||||
|
||||
lockBgView.isHidden = !(videoInfoModel?.is_lock ?? false)
|
||||
numLabel.textColor = videoInfoModel?.is_lock == true ? .colorFFFFFF(alpha: 0.5) : .colorFFFFFF()
|
||||
}
|
||||
}
|
||||
|
||||
var vp_isSelected: Bool = false {
|
||||
didSet {
|
||||
if vp_isSelected {
|
||||
contentView.vp_setGradientBorder()
|
||||
borderView.isHidden = false
|
||||
contentView.backgroundColor = .color05CEA0(alpha: 0.1)
|
||||
} else {
|
||||
contentView.vp_removeGradientBorder()
|
||||
borderView.isHidden = true
|
||||
contentView.backgroundColor = .colorFFFFFF(alpha: 0.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bgView: UIView = {
|
||||
private lazy var borderView: UIView = {
|
||||
let view = UIView()
|
||||
view.vp_setGradientBorder()
|
||||
view.layer.cornerRadius = 6
|
||||
@ -36,8 +39,6 @@ class VPEpisodeCell: VPCollectionViewCell {
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
|
||||
private lazy var numLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 14)
|
||||
@ -45,6 +46,16 @@ class VPEpisodeCell: VPCollectionViewCell {
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var lockBgView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "lock_bg_icon_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var lockImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "lock_icon_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
@ -63,16 +74,26 @@ extension VPEpisodeCell {
|
||||
contentView.layer.cornerRadius = 6
|
||||
contentView.layer.masksToBounds = true
|
||||
|
||||
// contentView.addSubview(bgView)
|
||||
contentView.addSubview(numLabel)
|
||||
contentView.addSubview(lockBgView)
|
||||
lockBgView.addSubview(lockImageView)
|
||||
contentView.addSubview(borderView)
|
||||
|
||||
// bgView.snp.makeConstraints { make in
|
||||
// make.edges.equalToSuperview()
|
||||
// }
|
||||
borderView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
numLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
}
|
||||
|
||||
lockBgView.snp.makeConstraints { make in
|
||||
make.top.right.equalToSuperview()
|
||||
}
|
||||
|
||||
lockImageView.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
105
Veloria/Class/Player/View/VPPlayerCoinBuyView.swift
Normal file
@ -0,0 +1,105 @@
|
||||
//
|
||||
// VPPlayerCoinBuyView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/6/3.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPPlayerCoinBuyView: UIView {
|
||||
|
||||
var dataArr: [VPPayTemplateItem] = [] {
|
||||
didSet {
|
||||
self.collectionView.reloadData()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var selectedIndex = 0
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.minimumLineSpacing = 10
|
||||
layout.minimumInteritemSpacing = 10
|
||||
layout.itemSize = .init(width: 106, height: 108)
|
||||
layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15)
|
||||
layout.scrollDirection = .horizontal
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: VPCollectionView = {
|
||||
let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
// collectionView.isScrollEnabled = false
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.register(VPCoinsBuyCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
private lazy var tipLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 0
|
||||
label.textColor = .colorFFFFFF(alpha: 0.5)
|
||||
label.font = .fontRegular(ofSize: 12)
|
||||
label.text = "kStoreTips".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPPlayerCoinBuyView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(collectionView)
|
||||
addSubview(tipLabel)
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
make.height.equalTo(collectionViewLayout.itemSize.height)
|
||||
// make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
tipLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-15)
|
||||
make.top.equalTo(collectionView.snp.bottom).offset(12)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource --------------
|
||||
extension VPPlayerCoinBuyView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPCoinsBuyCell
|
||||
cell.item = self.dataArr[indexPath.row]
|
||||
cell.vp_isSelected = indexPath.row == selectedIndex
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return self.dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
self.selectedIndex = indexPath.row
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
}
|
195
Veloria/Class/Player/View/VPPlayerRechargeView.swift
Normal file
@ -0,0 +1,195 @@
|
||||
//
|
||||
// VPPlayerRechargeView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/6/3.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPPlayerRechargeView: HWPanModalContentView {
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var bgView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
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 coinLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 13)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var coinIconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "coin_icon_07"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var scrollView: VPScrollView = {
|
||||
let scrollView = VPScrollView()
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var vipView: VPPlayerVipBuyView = {
|
||||
let view = VPPlayerVipBuyView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var coinView: VPPlayerCoinBuyView = {
|
||||
let view = VPPlayerCoinBuyView()
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
vp_setupUI()
|
||||
|
||||
updateCoin()
|
||||
|
||||
requestRechargeData()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
@objc private func handleCloseButton() {
|
||||
self.dismiss(animated: true) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: HWPanModalPresentable
|
||||
override func panScrollable() -> UIScrollView? {
|
||||
return scrollView
|
||||
}
|
||||
|
||||
override func longFormHeight() -> PanModalHeight {
|
||||
return PanModalHeightMake(.content, UIScreen.height * (2 / 3))
|
||||
}
|
||||
|
||||
override func showDragIndicator() -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
override func backgroundConfig() -> HWBackgroundConfig {
|
||||
let config = HWBackgroundConfig()
|
||||
config.backgroundAlpha = 0.6
|
||||
return config
|
||||
}
|
||||
|
||||
override func allowsDragToDismiss() -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
override func allowsTapBackgroundToDismiss() -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
override func allowsPullDownWhenShortState() -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
override func minVerticalVelocityToTriggerDismiss() -> CGFloat {
|
||||
return 0
|
||||
}
|
||||
|
||||
override func showsScrollableVerticalScrollIndicator() -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPPlayerRechargeView {
|
||||
|
||||
private func updateCoin() {
|
||||
let coinCountStr = "\(VPLoginManager.manager.userInfo?.totalCoin ?? 0)"
|
||||
let text = String(format: "Coins: %@".localized, coinCountStr)
|
||||
let coinRange = text.ocString().range(of: coinCountStr)
|
||||
|
||||
let string = NSMutableAttributedString(string: text)
|
||||
string.color = .colorFFFFFF()
|
||||
string.setColor(.color05CEA0(), range: coinRange)
|
||||
|
||||
coinLabel.attributedText = string
|
||||
}
|
||||
}
|
||||
|
||||
extension VPPlayerRechargeView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(bgView)
|
||||
addSubview(closeButton)
|
||||
addSubview(coinLabel)
|
||||
addSubview(coinIconImageView)
|
||||
addSubview(scrollView)
|
||||
scrollView.addSubview(vipView)
|
||||
scrollView.addSubview(coinView)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
closeButton.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-5)
|
||||
make.top.equalToSuperview().offset(5)
|
||||
make.width.equalTo(40)
|
||||
make.height.equalTo(40)
|
||||
}
|
||||
|
||||
coinLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.centerY.equalTo(coinIconImageView)
|
||||
}
|
||||
|
||||
coinIconImageView.snp.makeConstraints { make in
|
||||
make.left.equalTo(coinLabel.snp.right).offset(3)
|
||||
make.top.equalToSuperview().offset(40)
|
||||
}
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(56)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
vipView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
coinView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(vipView.snp.bottom).offset(20)
|
||||
make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 10))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPPlayerRechargeView {
|
||||
|
||||
private func requestRechargeData() {
|
||||
|
||||
VPWalletAPI.requestPayTemplate { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
if let model = model {
|
||||
self.vipView.dataArr = model.list_sub_vip ?? []
|
||||
self.coinView.dataArr = model.list_coins ?? []
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
144
Veloria/Class/Player/View/VPPlayerVipBuyView.swift
Normal file
@ -0,0 +1,144 @@
|
||||
//
|
||||
// VPPlayerVipBuyView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/6/3.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPPlayerVipBuyView: UIView {
|
||||
|
||||
var dataArr: [VPPayTemplateItem] = [] {
|
||||
didSet {
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var currentIndex: Int = 0
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.scrollDirection = .horizontal
|
||||
layout.minimumLineSpacing = 10
|
||||
layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15)
|
||||
layout.itemSize = .init(width: 332, height: 138)
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: VPCollectionView = {
|
||||
let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.register(VPVipBuyCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
private lazy var tipBgView: UIView = {
|
||||
let view = VPGradientView()
|
||||
view.colors = [UIColor.color05CEA0(alpha: 0.2).cgColor, UIColor.color05CEA0(alpha: 0).cgColor]
|
||||
view.locations = [0, 1]
|
||||
view.startPoint = .init(x: 0, y: 0.5)
|
||||
view.endPoint = .init(x: 1, y: 0.5)
|
||||
view.layer.cornerRadius = 8
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var tipLabel: UILabel = {
|
||||
|
||||
|
||||
let hText1 = "1 week".localized
|
||||
let text1 = "· " + String(format: "kVipPrivilegeText4".localized, hText1)
|
||||
|
||||
let hText2 = "8 days".localized
|
||||
let text2 = "· " + String(format: "kVipPrivilegeText5".localized, hText2)
|
||||
|
||||
let text3 = "· " + String(format: "kVipPrivilegeText6".localized)
|
||||
|
||||
let text = text1 + "\n" + text2 + "\n" + text3
|
||||
|
||||
let hRange1 = text.ocString().range(of: hText1)
|
||||
let hRange2 = text.ocString().range(of: hText2)
|
||||
|
||||
let string = NSMutableAttributedString(string: text)
|
||||
string.lineSpacing = 5
|
||||
string.color = .colorFFFFFF(alpha: 0.8)
|
||||
string.setColor(.color05CEA0(), range: hRange1)
|
||||
string.setColor(.color05CEA0(), range: hRange2)
|
||||
|
||||
|
||||
|
||||
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 12)
|
||||
label.attributedText = string
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPPlayerVipBuyView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(collectionView)
|
||||
addSubview(tipBgView)
|
||||
tipBgView.addSubview(tipLabel)
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
make.height.equalTo(collectionViewLayout.itemSize.height)
|
||||
}
|
||||
|
||||
tipBgView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.right.equalToSuperview().offset(-15)
|
||||
make.top.equalTo(collectionView.snp.bottom).offset(10)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
tipLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(14)
|
||||
make.right.lessThanOrEqualToSuperview().offset(-14)
|
||||
make.top.equalToSuperview().offset(10)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource --------------
|
||||
extension VPPlayerVipBuyView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPVipBuyCell
|
||||
cell.item = dataArr[indexPath.row]
|
||||
cell.vp_isSelected = indexPath.row == currentIndex
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
if currentIndex != indexPath.row {
|
||||
currentIndex = indexPath.row
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
92
Veloria/Class/Player/View/VPVideoLockView.swift
Normal file
@ -0,0 +1,92 @@
|
||||
//
|
||||
// VPVideoLockView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/6/3.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPVideoLockView: UIView {
|
||||
|
||||
var videoInfo: VPVideoInfoModel? {
|
||||
didSet {
|
||||
unlockButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
var clickUnlockButton: (() -> Void)?
|
||||
|
||||
private lazy var unlockButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.imagePlacement = .leading
|
||||
config.imagePadding = 10
|
||||
config.image = UIImage(named: "lock_icon_02")
|
||||
|
||||
let button = VPGradientButton(configuration: config)
|
||||
button.bt_setGradientBorder()
|
||||
button.colors = [UIColor.color05CEA0(alpha: 0.3).cgColor, UIColor.color7C174F(alpha: 0.3).cgColor]
|
||||
button.locations = [0, 1]
|
||||
button.startPoint = .init(x: 0, y: 0.3)
|
||||
button.endPoint = .init(x: 1, y: 0.8)
|
||||
button.layer.cornerRadius = 24
|
||||
button.layer.masksToBounds = true
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
let title = String(format: "Unlocking costs %@ coins".localized, "\(videoInfo?.coins ?? 0)")
|
||||
let string = AttributedString.createAttributedString(string: title, color: .colorFFFFFF(), font: .fontRegular(ofSize: 14))
|
||||
button.configuration?.attributedTitle = string
|
||||
}
|
||||
button.addTarget(self, action: #selector(handleUnlockButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var coinCountLabel: UILabel = {
|
||||
let userInfo = VPLoginManager.manager.userInfo
|
||||
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 12)
|
||||
label.textColor = .colorB5B5B5()
|
||||
label.text = String(format: "Balance: %@ Coins | %@ Bonus".localized, "\(userInfo?.coin_left_total ?? 0)", "\(userInfo?.send_coin_left_total ?? 0)")
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
backgroundColor = .color000000(alpha: 0.8)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func handleUnlockButton() {
|
||||
self.clickUnlockButton?()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPVideoLockView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(unlockButton)
|
||||
addSubview(coinCountLabel)
|
||||
|
||||
unlockButton.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(40)
|
||||
make.centerY.equalToSuperview()
|
||||
make.height.equalTo(48)
|
||||
}
|
||||
|
||||
coinCountLabel.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(unlockButton.snp.bottom).offset(10)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -17,9 +17,6 @@ class VPVideoPlayViewModel: NSObject {
|
||||
oldValue?.isCurrent = false
|
||||
oldValue?.pause()
|
||||
|
||||
// self.currentPlayer?.playerFinishHadle = { [weak self] in
|
||||
// self?.handlePlayFinish?()
|
||||
// }
|
||||
self.currentPlayer?.isCurrent = true
|
||||
self.currentPlayer?.rate = rateModel.rate.getRate()
|
||||
}
|
||||
@ -45,4 +42,6 @@ class VPVideoPlayViewModel: NSObject {
|
||||
var handlePlayTimeDidChange: ((_ time: Int) -> Void)?
|
||||
///选集
|
||||
var handleEpisode: (() -> Void)?
|
||||
|
||||
var handleUnlock: (() -> Void)?
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
//
|
||||
// VPRewardsViewController.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/6/3.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPRewardsViewController: VPCampaignWebViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
self.urlStr = kVPRewardsWebUrl
|
||||
super.viewDidLoad()
|
||||
|
||||
self.theme = nil
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -174,7 +174,6 @@ extension VPCoinsViewController: UICollectionViewDelegate, UICollectionViewDataS
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
vpLog(message: indexPath.row)
|
||||
self.selectedIndex = indexPath.row
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ class VPWalletHeaderView: UIView {
|
||||
coinCountLabel.text = "\(userInfo?.totalCoin ?? 0)"
|
||||
rechargeCoinView.count = userInfo?.coin_left_total ?? 0
|
||||
sendCoinView.count = userInfo?.send_coin_left_total ?? 0
|
||||
// coinCountLabel.text = "1234567890"
|
||||
}
|
||||
}
|
||||
|
||||
|
22
Veloria/Source/Assets.xcassets/icon/coin_icon_07.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "金币1 2@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "金币1 2@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/icon/coin_icon_07.imageset/金币1 2@2x.png
vendored
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/coin_icon_07.imageset/金币1 2@3x.png
vendored
Normal file
After Width: | Height: | Size: 4.6 KiB |
22
Veloria/Source/Assets.xcassets/icon/lock_bg_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Rectangle 26@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Rectangle 26@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/icon/lock_bg_icon_01.imageset/Rectangle 26@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/lock_bg_icon_01.imageset/Rectangle 26@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.3 KiB |
22
Veloria/Source/Assets.xcassets/icon/lock_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/icon/lock_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 384 B |
BIN
Veloria/Source/Assets.xcassets/icon/lock_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 502 B |
22
Veloria/Source/Assets.xcassets/icon/lock_icon_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/icon/lock_icon_02.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 478 B |
BIN
Veloria/Source/Assets.xcassets/icon/lock_icon_02.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 697 B |
@ -39,7 +39,6 @@
|
||||
"Donate" = "Donate";
|
||||
"Wallet" = "Wallet";
|
||||
"Store" = "Store";
|
||||
"Rewards" = "Rewards";
|
||||
"Favorites" = "Favorites";
|
||||
"Language" = "Language";
|
||||
"VIP" = "VIP";
|
||||
@ -63,6 +62,8 @@
|
||||
"VIP Record" = "VIP Record";
|
||||
"Total Coins" = "Total Coins";
|
||||
"Recharge" = "Recharge";
|
||||
"Unlocking costs %@ coins" = "Unlocking costs %@ coins";
|
||||
"Balance: %@ Coins | %@ Bonus" = "Balance: %@ Coins | %@ Bonus";
|
||||
|
||||
|
||||
"kHomeTitleText" = "10,000+ addictive shorts await!";
|
||||
@ -78,6 +79,10 @@
|
||||
"kVipPrivilegeText6" = "Auto renew, cancel anytime";
|
||||
//无网提示
|
||||
"kNetworkToast01" = "The service is abnormal. Check the network.";
|
||||
//解锁上一集提示
|
||||
"kLockPreviousEpisodeText" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
|
||||
//解锁失败
|
||||
"kLockFailText" = "Purchase failed, please try again later!";
|
||||
|
||||
|
||||
"kStoreTips" = "1. Coins are virtual items and cannot be refunded. Use it for this product.
|
||||
|