播放页面解锁功能开发
@ -172,6 +172,10 @@
|
|||||||
F39855482E33928400E2D28D /* BRStoreCoinBigCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39855472E33928400E2D28D /* BRStoreCoinBigCell.swift */; };
|
F39855482E33928400E2D28D /* BRStoreCoinBigCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39855472E33928400E2D28D /* BRStoreCoinBigCell.swift */; };
|
||||||
F398554A2E33929C00E2D28D /* BRStoreCoinCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39855492E33929C00E2D28D /* BRStoreCoinCell.swift */; };
|
F398554A2E33929C00E2D28D /* BRStoreCoinCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39855492E33929C00E2D28D /* BRStoreCoinCell.swift */; };
|
||||||
F398554C2E3392C200E2D28D /* BRStoreCoinSmallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F398554B2E3392C200E2D28D /* BRStoreCoinSmallCell.swift */; };
|
F398554C2E3392C200E2D28D /* BRStoreCoinSmallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F398554B2E3392C200E2D28D /* BRStoreCoinSmallCell.swift */; };
|
||||||
|
F398554E2E34699F00E2D28D /* BRVideoLockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F398554D2E34699F00E2D28D /* BRVideoLockView.swift */; };
|
||||||
|
F39855502E34782200E2D28D /* BRVideoUnlockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F398554F2E34782200E2D28D /* BRVideoUnlockModel.swift */; };
|
||||||
|
F39855522E347BDE00E2D28D /* BRVideoRechargeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39855512E347BDE00E2D28D /* BRVideoRechargeView.swift */; };
|
||||||
|
F39855542E34A49500E2D28D /* VPPayDataRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39855532E34A49500E2D28D /* VPPayDataRequest.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@ -355,6 +359,10 @@
|
|||||||
F39855472E33928400E2D28D /* BRStoreCoinBigCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRStoreCoinBigCell.swift; sourceTree = "<group>"; };
|
F39855472E33928400E2D28D /* BRStoreCoinBigCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRStoreCoinBigCell.swift; sourceTree = "<group>"; };
|
||||||
F39855492E33929C00E2D28D /* BRStoreCoinCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRStoreCoinCell.swift; sourceTree = "<group>"; };
|
F39855492E33929C00E2D28D /* BRStoreCoinCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRStoreCoinCell.swift; sourceTree = "<group>"; };
|
||||||
F398554B2E3392C200E2D28D /* BRStoreCoinSmallCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRStoreCoinSmallCell.swift; sourceTree = "<group>"; };
|
F398554B2E3392C200E2D28D /* BRStoreCoinSmallCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRStoreCoinSmallCell.swift; sourceTree = "<group>"; };
|
||||||
|
F398554D2E34699F00E2D28D /* BRVideoLockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRVideoLockView.swift; sourceTree = "<group>"; };
|
||||||
|
F398554F2E34782200E2D28D /* BRVideoUnlockModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRVideoUnlockModel.swift; sourceTree = "<group>"; };
|
||||||
|
F39855512E347BDE00E2D28D /* BRVideoRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRVideoRechargeView.swift; sourceTree = "<group>"; };
|
||||||
|
F39855532E34A49500E2D28D /* VPPayDataRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPPayDataRequest.swift; sourceTree = "<group>"; };
|
||||||
F70FA1F4169364C4C53534CE /* Pods-BeeReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.release.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.release.xcconfig"; sourceTree = "<group>"; };
|
F70FA1F4169364C4C53534CE /* Pods-BeeReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.release.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@ -816,6 +824,8 @@
|
|||||||
BF02B7EA2E2E388800172177 /* BREpisodeMenuView.swift */,
|
BF02B7EA2E2E388800172177 /* BREpisodeMenuView.swift */,
|
||||||
BF02B7F02E2E55E300172177 /* BRRateSelectorView.swift */,
|
BF02B7F02E2E55E300172177 /* BRRateSelectorView.swift */,
|
||||||
BF02B7F22E2E571600172177 /* BRRateSelectorCell.swift */,
|
BF02B7F22E2E571600172177 /* BRRateSelectorCell.swift */,
|
||||||
|
F398554D2E34699F00E2D28D /* BRVideoLockView.swift */,
|
||||||
|
F39855512E347BDE00E2D28D /* BRVideoRechargeView.swift */,
|
||||||
);
|
);
|
||||||
path = View;
|
path = View;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -827,6 +837,7 @@
|
|||||||
BFC676802E122733006659E5 /* BRPlayerProtocol.swift */,
|
BFC676802E122733006659E5 /* BRPlayerProtocol.swift */,
|
||||||
BFC676862E122E36006659E5 /* BRVideoDetailModel.swift */,
|
BFC676862E122E36006659E5 /* BRVideoDetailModel.swift */,
|
||||||
BF02B7EE2E2E4BFD00172177 /* BRRateModel.swift */,
|
BF02B7EE2E2E4BFD00172177 /* BRRateModel.swift */,
|
||||||
|
F398554F2E34782200E2D28D /* BRVideoUnlockModel.swift */,
|
||||||
);
|
);
|
||||||
path = Model;
|
path = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1073,6 +1084,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
F398553D2E336D3000E2D28D /* BRPayDateModel.swift */,
|
F398553D2E336D3000E2D28D /* BRPayDateModel.swift */,
|
||||||
|
F39855532E34A49500E2D28D /* VPPayDataRequest.swift */,
|
||||||
);
|
);
|
||||||
path = Model;
|
path = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1207,12 +1219,14 @@
|
|||||||
BFC676B12E137D2F006659E5 /* BRPopularPicksViewController.swift in Sources */,
|
BFC676B12E137D2F006659E5 /* BRPopularPicksViewController.swift in Sources */,
|
||||||
BF02B7FC2E2F262F00172177 /* BRGradientView.swift in Sources */,
|
BF02B7FC2E2F262F00172177 /* BRGradientView.swift in Sources */,
|
||||||
BFC676692E0E34DA006659E5 /* BRUserAPI.swift in Sources */,
|
BFC676692E0E34DA006659E5 /* BRUserAPI.swift in Sources */,
|
||||||
|
F398554E2E34699F00E2D28D /* BRVideoLockView.swift in Sources */,
|
||||||
BFC676782E0E9553006659E5 /* BRSpotlightMainBaseCell.swift in Sources */,
|
BFC676782E0E9553006659E5 /* BRSpotlightMainBaseCell.swift in Sources */,
|
||||||
BFC676732E0E938B006659E5 /* BRTableView.swift in Sources */,
|
BFC676732E0E938B006659E5 /* BRTableView.swift in Sources */,
|
||||||
BFC676932E126A62006659E5 /* BRSpotlightNewMainCell.swift in Sources */,
|
BFC676932E126A62006659E5 /* BRSpotlightNewMainCell.swift in Sources */,
|
||||||
BFC6768D2E123D6E006659E5 /* AttributedString+BRAdd.swift in Sources */,
|
BFC6768D2E123D6E006659E5 /* AttributedString+BRAdd.swift in Sources */,
|
||||||
BF02B8392E30B30400172177 /* AlignedCollectionViewFlowLayout.swift in Sources */,
|
BF02B8392E30B30400172177 /* AlignedCollectionViewFlowLayout.swift in Sources */,
|
||||||
BF3A56882E30E0DD009E5CF9 /* BREmpty.swift in Sources */,
|
BF3A56882E30E0DD009E5CF9 /* BREmpty.swift in Sources */,
|
||||||
|
F39855542E34A49500E2D28D /* VPPayDataRequest.swift in Sources */,
|
||||||
BF3338F52E1616B200B10F76 /* BRExploreControlView.swift in Sources */,
|
BF3338F52E1616B200B10F76 /* BRExploreControlView.swift in Sources */,
|
||||||
F398552D2E33126D00E2D28D /* BRMineCoinItemView.swift in Sources */,
|
F398552D2E33126D00E2D28D /* BRMineCoinItemView.swift in Sources */,
|
||||||
BF692B132E0A7B9000A5C2DA /* BRUserInfo.swift in Sources */,
|
BF692B132E0A7B9000A5C2DA /* BRUserInfo.swift in Sources */,
|
||||||
@ -1250,6 +1264,7 @@
|
|||||||
BF692B782E0D3A1200A5C2DA /* BRHomeModuleItem.swift in Sources */,
|
BF692B782E0D3A1200A5C2DA /* BRHomeModuleItem.swift in Sources */,
|
||||||
BF692B5A2E0AAADD00A5C2DA /* BRPlayerListCell.swift in Sources */,
|
BF692B5A2E0AAADD00A5C2DA /* BRPlayerListCell.swift in Sources */,
|
||||||
BF02B8312E30897700172177 /* BRSearchHomeView.swift in Sources */,
|
BF02B8312E30897700172177 /* BRSearchHomeView.swift in Sources */,
|
||||||
|
F39855502E34782200E2D28D /* BRVideoUnlockModel.swift in Sources */,
|
||||||
F398554A2E33929C00E2D28D /* BRStoreCoinCell.swift in Sources */,
|
F398554A2E33929C00E2D28D /* BRStoreCoinCell.swift in Sources */,
|
||||||
BF3A568C2E30EBA2009E5CF9 /* BRHomePlayRecordButton.swift in Sources */,
|
BF3A568C2E30EBA2009E5CF9 /* BRHomePlayRecordButton.swift in Sources */,
|
||||||
BF692B162E0A7CD600A5C2DA /* BRHUD.swift in Sources */,
|
BF692B162E0A7CD600A5C2DA /* BRHUD.swift in Sources */,
|
||||||
@ -1287,6 +1302,7 @@
|
|||||||
F39855312E33620200E2D28D /* BRMineStoreCell.swift in Sources */,
|
F39855312E33620200E2D28D /* BRMineStoreCell.swift in Sources */,
|
||||||
BF692B182E0A7D8900A5C2DA /* BRToast.swift in Sources */,
|
BF692B182E0A7D8900A5C2DA /* BRToast.swift in Sources */,
|
||||||
BF692B0E2E0A7AF300A5C2DA /* UserDefaults+BRAdd.swift in Sources */,
|
BF692B0E2E0A7AF300A5C2DA /* UserDefaults+BRAdd.swift in Sources */,
|
||||||
|
F39855522E347BDE00E2D28D /* BRVideoRechargeView.swift in Sources */,
|
||||||
BF02B8082E2F616E00172177 /* BRFavoritesViewController.swift in Sources */,
|
BF02B8082E2F616E00172177 /* BRFavoritesViewController.swift in Sources */,
|
||||||
BF3338FD2E1626B000B10F76 /* BRPlayerControlProtocol.swift in Sources */,
|
BF3338FD2E1626B000B10F76 /* BRPlayerControlProtocol.swift in Sources */,
|
||||||
BF692B582E0AAA6F00A5C2DA /* UIScreen+BRAdd.swift in Sources */,
|
BF692B582E0AAA6F00A5C2DA /* UIScreen+BRAdd.swift in Sources */,
|
||||||
|
@ -186,4 +186,8 @@ extension UIColor {
|
|||||||
static func colorFFB635(alpha: CGFloat = 1) -> UIColor {
|
static func colorFFB635(alpha: CGFloat = 1) -> UIColor {
|
||||||
return UIColor(rgb: 0xFFB635, alpha: alpha)
|
return UIColor(rgb: 0xFFB635, alpha: alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func colorB5B5B5(alpha: CGFloat = 1) -> UIColor {
|
||||||
|
return UIColor(rgb: 0xB5B5B5, alpha: alpha)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +134,38 @@ class BRVideoAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///上报播放时长
|
||||||
|
static func requestUploadPlayTime(shortPlayId: String, videoId: String, seconds: Int) {
|
||||||
|
|
||||||
|
var param = BRNetworkParameters(path: "/uploadHistorySeconds")
|
||||||
|
param.isLoding = false
|
||||||
|
param.isToast = false
|
||||||
|
param.parameters = [
|
||||||
|
"video_id" : videoId,
|
||||||
|
"short_play_id" : shortPlayId,
|
||||||
|
"play_seconds" : seconds
|
||||||
|
]
|
||||||
|
|
||||||
|
BRNetwork.request(parameters: param) { (response: BRNetworkResponse<String>) in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///金币解锁视频
|
||||||
|
static func requestCoinUnlockVideo(shortPlayId: String, videoId: String, completer: ((_ model: BRVideoUnlockModel?) -> Void)?) {
|
||||||
|
|
||||||
|
var param = BRNetworkParameters(path: "/buy_video")
|
||||||
|
param.isLoding = true
|
||||||
|
param.parameters = [
|
||||||
|
"short_play_id" : shortPlayId,
|
||||||
|
"video_id" : videoId,
|
||||||
|
]
|
||||||
|
|
||||||
|
BRNetwork.request(parameters: param) { (response: BRNetworkResponse<BRVideoUnlockModel>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,9 +72,9 @@ class BRPanModalContentView: HWPanModalContentView {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override func minVerticalVelocityToTriggerDismiss() -> CGFloat {
|
// override func minVerticalVelocityToTriggerDismiss() -> CGFloat {
|
||||||
return 0
|
// return 0
|
||||||
}
|
// }
|
||||||
|
|
||||||
override func showsScrollableVerticalScrollIndicator() -> Bool {
|
override func showsScrollableVerticalScrollIndicator() -> Bool {
|
||||||
return false
|
return false
|
||||||
|
@ -49,6 +49,7 @@ class BRPlayerListViewController: BRViewController {
|
|||||||
private(set) lazy var viewModel: BRPlayerViewModel = {
|
private(set) lazy var viewModel: BRPlayerViewModel = {
|
||||||
let vm = BRPlayerViewModel()
|
let vm = BRPlayerViewModel()
|
||||||
vm.delegate = self
|
vm.delegate = self
|
||||||
|
vm.playerListVC = self
|
||||||
return vm
|
return vm
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -321,6 +322,14 @@ extension BRPlayerListViewController: BRPlayerViewModelDelegate {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func br_playProgressDidChange(viewModel: BRPlayerViewModel, time: TimeInterval) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func br_needUpdateAllData(viewModel: BRPlayerViewModel, scrollTo indexPath: IndexPath?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BRPlayerListViewController {
|
extension BRPlayerListViewController {
|
||||||
|
@ -23,6 +23,9 @@ class BRVideoDetailViewController: BRPlayerListViewController {
|
|||||||
|
|
||||||
private var detailArr: [BRVideoDetailModel] = []
|
private var detailArr: [BRVideoDetailModel] = []
|
||||||
|
|
||||||
|
///上一次上报播放时长的节点
|
||||||
|
private var lastUploadTime: TimeInterval = 0
|
||||||
|
|
||||||
//MARK: UI属性
|
//MARK: UI属性
|
||||||
private lazy var backButton: UIButton = {
|
private lazy var backButton: UIButton = {
|
||||||
let button = UIButton(type: .custom)
|
let button = UIButton(type: .custom)
|
||||||
@ -66,8 +69,21 @@ class BRVideoDetailViewController: BRPlayerListViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func play() {
|
override func play() {
|
||||||
super.play()
|
let videoInfo = self.viewModel.currentPlayer?.videoInfo
|
||||||
BRVideoAPI.requestAddPlayHistory(videoId: self.viewModel.currentPlayer?.videoInfo?.short_play_video_id, shortPlayId: self.viewModel.currentPlayer?.videoInfo?.short_play_id)
|
guard videoInfo?.is_lock == true else {
|
||||||
|
super.play()
|
||||||
|
BRVideoAPI.requestAddPlayHistory(videoId: self.viewModel.currentPlayer?.videoInfo?.short_play_video_id, shortPlayId: self.viewModel.currentPlayer?.videoInfo?.short_play_id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
self.pause()
|
||||||
|
|
||||||
|
let myCoins = BRLoginManager.manager.userInfo?.totalCoin ?? 0
|
||||||
|
let coins = videoInfo?.coins ?? 0
|
||||||
|
if myCoins < coins, self.viewModel.currentPlayer?.hasLastEpisodeUnlocked != true {
|
||||||
|
self.viewModel.openRechargeView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -116,6 +132,18 @@ extension BRVideoDetailViewController {
|
|||||||
|
|
||||||
self.popUpView = view
|
self.popUpView = view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func br_playProgressDidChange(viewModel: BRPlayerViewModel, time: TimeInterval) {
|
||||||
|
if (time >= lastUploadTime + 5 || time < lastUploadTime) && time >= 5 {
|
||||||
|
lastUploadTime = time
|
||||||
|
self.viewModel.uploadPlayTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func br_needUpdateAllData(viewModel: BRPlayerViewModel, scrollTo indexPath: IndexPath?) {
|
||||||
|
self.requestDetailData(indexPath: indexPath)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: -------------- BRPlayerListViewControllerDataSource BRPlayerListViewControllerDelegate --------------
|
//MARK: -------------- BRPlayerListViewControllerDataSource BRPlayerListViewControllerDelegate --------------
|
||||||
@ -147,6 +175,8 @@ extension BRVideoDetailViewController: BRPlayerListViewControllerDataSource, BRP
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BRVideoDetailViewController {
|
extension BRVideoDetailViewController {
|
||||||
@ -169,6 +199,23 @@ extension BRVideoDetailViewController {
|
|||||||
self.reloadData { [weak self] in
|
self.reloadData { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.play()
|
self.play()
|
||||||
|
var targetIndexPath = IndexPath(row: 0, section: 0)
|
||||||
|
|
||||||
|
if let indexPath = indexPath, indexPath.row < (model.episodeList?.count ?? 0) {
|
||||||
|
targetIndexPath = indexPath
|
||||||
|
|
||||||
|
} else if let videoInfo = model.video_info {
|
||||||
|
var row: Int?
|
||||||
|
model.episodeList?.enumerated().forEach({
|
||||||
|
if $1.id == videoInfo.id {
|
||||||
|
row = $0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if let row = row {
|
||||||
|
targetIndexPath = .init(row: row, section: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.scrollToItem(indexPath: targetIndexPath, animated: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class BRRateModel: NSObject {
|
|||||||
|
|
||||||
static func getAllRate() -> [BRRateModel] {
|
static func getAllRate() -> [BRRateModel] {
|
||||||
return [
|
return [
|
||||||
BRRateModel(rate: .x0_25),
|
// BRRateModel(rate: .x0_25),
|
||||||
BRRateModel(rate: .x0_5),
|
BRRateModel(rate: .x0_5),
|
||||||
BRRateModel(rate: .x0_75),
|
BRRateModel(rate: .x0_75),
|
||||||
BRRateModel(rate: .x1),
|
BRRateModel(rate: .x1),
|
||||||
|
26
BeeReel/Class/Player/Model/BRVideoUnlockModel.swift
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// BRVideoUnlockModel.swift
|
||||||
|
// BeeReel
|
||||||
|
//
|
||||||
|
// Created by 长沙鸿瑶 on 2025/7/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class BRVideoUnlockModel: BRModel, SmartCodable {
|
||||||
|
|
||||||
|
enum ResponseStatus: String, SmartCaseDefaultable {
|
||||||
|
///前面还有没购买的剧
|
||||||
|
case jump = "jump"
|
||||||
|
///没找到视频
|
||||||
|
case noPlay = "no_play"
|
||||||
|
///金币不足跳充值
|
||||||
|
case notEnough = "not_enough"
|
||||||
|
///购买成功
|
||||||
|
case success = "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
var status: ResponseStatus?
|
||||||
|
|
||||||
|
}
|
@ -19,6 +19,12 @@ class BRDetailControlView: BRPlayerControlView {
|
|||||||
override var videoInfo: BRVideoInfoModel? {
|
override var videoInfo: BRVideoInfoModel? {
|
||||||
didSet {
|
didSet {
|
||||||
epButton.videoInfo = videoInfo
|
epButton.videoInfo = videoInfo
|
||||||
|
videoLockView.videoInfo = videoInfo
|
||||||
|
if videoInfo?.is_lock == true {
|
||||||
|
self.videoLockView.isHidden = false
|
||||||
|
} else {
|
||||||
|
self.videoLockView.isHidden = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +114,14 @@ class BRDetailControlView: BRPlayerControlView {
|
|||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var videoLockView: BRVideoLockView = {
|
||||||
|
let view = BRVideoLockView()
|
||||||
|
view.clickUnlockButton = { [weak self] in
|
||||||
|
self?.viewModel?.clickUnlockButton()
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
|
||||||
@ -133,7 +147,6 @@ class BRDetailControlView: BRPlayerControlView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BRDetailControlView {
|
extension BRDetailControlView {
|
||||||
@ -198,6 +211,7 @@ extension BRDetailControlView {
|
|||||||
addSubview(rateButton)
|
addSubview(rateButton)
|
||||||
addSubview(nameLabel)
|
addSubview(nameLabel)
|
||||||
addSubview(favoriteButton)
|
addSubview(favoriteButton)
|
||||||
|
addSubview(videoLockView)
|
||||||
|
|
||||||
progressView.snp.makeConstraints { make in
|
progressView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview()
|
make.left.equalToSuperview()
|
||||||
@ -233,6 +247,10 @@ extension BRDetailControlView {
|
|||||||
make.right.equalToSuperview().offset(-7)
|
make.right.equalToSuperview().offset(-7)
|
||||||
make.bottom.equalTo(progressView.snp.top).offset(-10)
|
make.bottom.equalTo(progressView.snp.top).offset(-10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
videoLockView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ class BREpisodeSelectorCell: BRCollectionViewCell {
|
|||||||
var model: BRVideoInfoModel? {
|
var model: BRVideoInfoModel? {
|
||||||
didSet {
|
didSet {
|
||||||
epLabel.text = model?.episode
|
epLabel.text = model?.episode
|
||||||
|
|
||||||
|
lockView.isHidden = !(model?.is_lock ?? false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +41,19 @@ class BREpisodeSelectorCell: BRCollectionViewCell {
|
|||||||
return imageView
|
return imageView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var lockView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .colorE3FC37()
|
||||||
|
view.br_setRoundedCorner(topLeft: 0, topRight: 6, bottomLeft: 6, bottomRight: 0)
|
||||||
|
let icon = UIImageView(image: UIImage(named: "Frame 3"))
|
||||||
|
view.addSubview(icon)
|
||||||
|
icon.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
@ -51,6 +66,7 @@ class BREpisodeSelectorCell: BRCollectionViewCell {
|
|||||||
|
|
||||||
contentView.addSubview(epLabel)
|
contentView.addSubview(epLabel)
|
||||||
contentView.addSubview(lightImageView)
|
contentView.addSubview(lightImageView)
|
||||||
|
contentView.addSubview(lockView)
|
||||||
|
|
||||||
epLabel.snp.makeConstraints { make in
|
epLabel.snp.makeConstraints { make in
|
||||||
make.center.equalToSuperview()
|
make.center.equalToSuperview()
|
||||||
@ -60,6 +76,12 @@ class BREpisodeSelectorCell: BRCollectionViewCell {
|
|||||||
make.right.top.equalToSuperview()
|
make.right.top.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lockView.snp.makeConstraints { make in
|
||||||
|
make.top.right.equalToSuperview()
|
||||||
|
make.width.equalTo(18)
|
||||||
|
make.height.equalTo(12)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor required init?(coder: NSCoder) {
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
@ -88,7 +88,17 @@ class BRPlayerControlView: UIView, BRPlayerControlProtocol {
|
|||||||
self.viewModel?.switchPlayAndPause()
|
self.viewModel?.switchPlayAndPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updatePlayIconState() {
|
||||||
|
if videoInfo?.is_lock == true {
|
||||||
|
self.playIconImageView.isHidden = true
|
||||||
|
} else {
|
||||||
|
if isCurrent == true, self.viewModel?.isPlaying != true {
|
||||||
|
self.playIconImageView.isHidden = false
|
||||||
|
} else {
|
||||||
|
self.playIconImageView.isHidden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,13 +117,6 @@ extension BRPlayerControlView {
|
|||||||
|
|
||||||
extension BRPlayerControlView {
|
extension BRPlayerControlView {
|
||||||
|
|
||||||
private func updatePlayIconState() {
|
|
||||||
if isCurrent == true, self.viewModel?.isPlaying != true {
|
|
||||||
self.playIconImageView.isHidden = false
|
|
||||||
} else {
|
|
||||||
self.playIconImageView.isHidden = true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,9 @@ class BRPlayerListCell: BRCollectionViewCell, BRPlayerProtocol {
|
|||||||
self.player.seek(toTime: time)
|
self.player.seek(toTime: time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func seekTo(time: TimeInterval) {
|
||||||
|
self.player.seek(toTime: time)
|
||||||
|
}
|
||||||
|
|
||||||
var ControlViewClass: BRPlayerControlView.Type {
|
var ControlViewClass: BRPlayerControlView.Type {
|
||||||
return BRPlayerControlView.self
|
return BRPlayerControlView.self
|
||||||
@ -144,6 +147,7 @@ extension BRPlayerListCell: BRPlayerDelegate {
|
|||||||
} else {
|
} else {
|
||||||
self.controlView.progress = time / player.duration
|
self.controlView.progress = time / player.duration
|
||||||
}
|
}
|
||||||
|
self.viewModel?.playProgressDidChange(time: time)
|
||||||
}
|
}
|
||||||
|
|
||||||
func br_playerInBufferToPlay(_ player: BRPlayer) {
|
func br_playerInBufferToPlay(_ player: BRPlayer) {
|
||||||
@ -153,4 +157,11 @@ extension BRPlayerListCell: BRPlayerDelegate {
|
|||||||
func br_playerBufferingCompleted(_ player: BRPlayer) {
|
func br_playerBufferingCompleted(_ player: BRPlayer) {
|
||||||
self.controlView.isLoading = false
|
self.controlView.isLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func br_playerReadyToPlay(_ player: BRPlayer) {
|
||||||
|
let time = TimeInterval(self.videoInfo?.play_seconds ?? 0) / 1000
|
||||||
|
if time > 1 {
|
||||||
|
self.seekTo(time: time)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
128
BeeReel/Class/Player/View/BRVideoLockView.swift
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
//
|
||||||
|
// BRVideoLockView.swift
|
||||||
|
// BeeReel
|
||||||
|
//
|
||||||
|
// Created by 长沙鸿瑶 on 2025/7/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class BRVideoLockView: UIView {
|
||||||
|
|
||||||
|
|
||||||
|
var videoInfo: BRVideoInfoModel? {
|
||||||
|
didSet {
|
||||||
|
lockButton.setNeedsUpdateConfiguration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var clickUnlockButton: (() -> Void)?
|
||||||
|
|
||||||
|
private lazy var lockIconView: UIImageView = {
|
||||||
|
let view = UIImageView(image: UIImage(named: "Frame 4"))
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bottomView: UIView = {
|
||||||
|
let view = UIImageView(image: UIImage(named: "bg"))
|
||||||
|
view.isUserInteractionEnabled = true
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontBold(ofSize: 18)
|
||||||
|
label.textColor = .colorFFFFFF()
|
||||||
|
label.text = "Unlock to Continue".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var lockButton: UIButton = {
|
||||||
|
var config = UIButton.Configuration.plain()
|
||||||
|
config.background.image = UIImage(named: "bg 1")
|
||||||
|
config.image = UIImage(named: "Frame 5")
|
||||||
|
config.imagePadding = 10
|
||||||
|
|
||||||
|
let button = UIButton(configuration: config)
|
||||||
|
button.configurationUpdateHandler = { [weak self] button in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
let title = "Unlocking costs ## Coins".localizedReplace(text: "\(videoInfo?.coins ?? 0)")
|
||||||
|
|
||||||
|
button.configuration?.attributedTitle = AttributedString.br_createAttributedString(string: title, color: .color1C1C1C(), font: .fontRegular(ofSize: 14))
|
||||||
|
}
|
||||||
|
button.addTarget(self, action: #selector(handleUnlockButton), for: .touchUpInside)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var totalCoinsLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontRegular(ofSize: 12)
|
||||||
|
label.textColor = .colorB5B5B5()
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
backgroundColor = .color000000(alpha: 0.4)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUserInfo), name: BRLoginManager.userInfoUpdateNotification, object: nil)
|
||||||
|
|
||||||
|
updateUserInfo()
|
||||||
|
br_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func updateUserInfo() {
|
||||||
|
let userInfo = BRLoginManager.manager.userInfo
|
||||||
|
totalCoinsLabel.text = "Balance: ## Coins".localizedReplace(text: "\(userInfo?.totalCoin ?? 0)")
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func handleUnlockButton() {
|
||||||
|
self.clickUnlockButton?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BRVideoLockView {
|
||||||
|
|
||||||
|
private func br_setupUI() {
|
||||||
|
addSubview(lockIconView)
|
||||||
|
addSubview(bottomView)
|
||||||
|
bottomView.addSubview(titleLabel)
|
||||||
|
bottomView.addSubview(lockButton)
|
||||||
|
bottomView.addSubview(totalCoinsLabel)
|
||||||
|
|
||||||
|
lockIconView.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.height.equalTo(UIScreen.tabbarSafeBottomMargin + 222)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(26)
|
||||||
|
}
|
||||||
|
|
||||||
|
lockButton.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.width.equalTo(260)
|
||||||
|
make.height.equalTo(48)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCoinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 10))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
232
BeeReel/Class/Player/View/BRVideoRechargeView.swift
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
//
|
||||||
|
// BRVideoRechargeView.swift
|
||||||
|
// BeeReel
|
||||||
|
//
|
||||||
|
// Created by 长沙鸿瑶 on 2025/7/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class BRVideoRechargeView: BRPanModalContentView {
|
||||||
|
|
||||||
|
var buyCoinsFinishBlock: (() -> Void)?
|
||||||
|
var buyVipFinishBlock: (() -> Void)?
|
||||||
|
|
||||||
|
var payDataModel: BRPayDateModel? {
|
||||||
|
didSet {
|
||||||
|
self.stackView.br_removeAllArrangedSubview()
|
||||||
|
self.vipView.list = payDataModel?.list_sub_vip ?? []
|
||||||
|
self.coinView.list = payDataModel?.list_coins ?? []
|
||||||
|
|
||||||
|
if let sort = payDataModel?.sort, sort.count > 0 {
|
||||||
|
sort.forEach {
|
||||||
|
if $0 == .vip, payDataModel?.list_sub_vip?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.vipView)
|
||||||
|
} else if $0 == .coin, payDataModel?.list_coins?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.coinView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if payDataModel?.list_sub_vip?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.vipView)
|
||||||
|
}
|
||||||
|
if payDataModel?.list_coins?.isEmpty == false {
|
||||||
|
self.stackView.addArrangedSubview(self.coinView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setNeedsLayoutUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unlockCoin: Int? {
|
||||||
|
didSet {
|
||||||
|
if let unlockCoin = self.unlockCoin, unlockCoin > 0 {
|
||||||
|
unlockCoinsView.isHidden = false
|
||||||
|
} else {
|
||||||
|
unlockCoinsView.isHidden = true
|
||||||
|
}
|
||||||
|
unlockCoinsView.setNeedsUpdateConfiguration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var shortPlayId: String? {
|
||||||
|
didSet {
|
||||||
|
vipView.shortPlayId = shortPlayId
|
||||||
|
coinView.shortPlayId = shortPlayId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var videoId: String? {
|
||||||
|
didSet {
|
||||||
|
vipView.videoId = videoId
|
||||||
|
coinView.videoId = videoId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var coinIconView: UIView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "Frame 6"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinTitleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontMedium(ofSize: 13)
|
||||||
|
label.textColor = .colorFFFFFF()
|
||||||
|
label.text = "My Coins:".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontMedium(ofSize: 13)
|
||||||
|
label.textColor = .colorE3FC37()
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var scrollView: BRScrollView = {
|
||||||
|
let scrollView = BRScrollView()
|
||||||
|
scrollView.bounces = false
|
||||||
|
return scrollView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var unlockCoinsView: UIButton = {
|
||||||
|
var config = UIButton.Configuration.plain()
|
||||||
|
config.background.backgroundColor = .colorE3FC37()
|
||||||
|
config.image = UIImage(named: "Frame 6")
|
||||||
|
config.imagePadding = 2
|
||||||
|
config.imagePlacement = .trailing
|
||||||
|
config.contentInsets = .init(top: 0, leading: 10, bottom: 0, trailing: 10)
|
||||||
|
|
||||||
|
let button = UIButton(configuration: config)
|
||||||
|
button.layer.cornerRadius = 13
|
||||||
|
button.layer.masksToBounds = true
|
||||||
|
button.isUserInteractionEnabled = false
|
||||||
|
button.configurationUpdateHandler = { [weak self] button in
|
||||||
|
guard let self = self else { return }
|
||||||
|
let title = "Unlock:".localized
|
||||||
|
let coins = " \(unlockCoin ?? 0)"
|
||||||
|
|
||||||
|
var attributedTitle = AttributedString.br_createAttributedString(string: title + coins, color: .color1C1C1C(), font: .fontRegular(ofSize: 13))
|
||||||
|
if let range = attributedTitle.range(of: coins) {
|
||||||
|
attributedTitle[range].font = UIFont.fontMedium(ofSize: 13)
|
||||||
|
attributedTitle[range].foregroundColor = UIColor.colorFF7489()
|
||||||
|
}
|
||||||
|
button.configuration?.attributedTitle = attributedTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var stackView: UIStackView = {
|
||||||
|
let stackView = UIStackView()
|
||||||
|
stackView.axis = .vertical
|
||||||
|
stackView.spacing = 12
|
||||||
|
return stackView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var vipView: BRStoreVipView = {
|
||||||
|
let view = BRStoreVipView()
|
||||||
|
view.buyFinishBlock = { [weak self] in
|
||||||
|
self?.buyVipFinishBlock?()
|
||||||
|
self?.dismiss(animated: true) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinView: BRStoreCoinView = {
|
||||||
|
let view = BRStoreCoinView()
|
||||||
|
view.buyFinishBlock = { [weak self] in
|
||||||
|
self?.buyCoinsFinishBlock?()
|
||||||
|
self?.dismiss(animated: true) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUserInfo), name: BRLoginManager.userInfoUpdateNotification, object: nil)
|
||||||
|
self.contentHeight = UIScreen.height - UIScreen.navBarHeight
|
||||||
|
self.mainScrollView = self.scrollView
|
||||||
|
|
||||||
|
br_setupUI()
|
||||||
|
|
||||||
|
updateUserInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override func allowsPullDownWhenShortState() -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override func allowsDragToDismiss() -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BRVideoRechargeView {
|
||||||
|
|
||||||
|
private func br_setupUI() {
|
||||||
|
addSubview(scrollView)
|
||||||
|
scrollView.addSubview(stackView)
|
||||||
|
addSubview(coinTitleLabel)
|
||||||
|
addSubview(coinLabel)
|
||||||
|
addSubview(coinIconView)
|
||||||
|
addSubview(unlockCoinsView)
|
||||||
|
|
||||||
|
scrollView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(50)
|
||||||
|
}
|
||||||
|
|
||||||
|
stackView.snp.makeConstraints { make in
|
||||||
|
make.top.left.equalToSuperview()
|
||||||
|
make.width.equalTo(UIScreen.width)
|
||||||
|
make.bottom.equalToSuperview().offset(-UIScreen.tabbarSafeBottomMargin - 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinTitleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(15)
|
||||||
|
make.centerY.equalTo(coinIconView)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(coinTitleLabel.snp.right)
|
||||||
|
make.centerY.equalTo(coinIconView)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinIconView.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(coinLabel.snp.right).offset(2)
|
||||||
|
make.top.equalToSuperview().offset(18)
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockCoinsView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(coinIconView)
|
||||||
|
make.right.equalToSuperview().offset(-15)
|
||||||
|
make.height.equalTo(26)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension BRVideoRechargeView {
|
||||||
|
|
||||||
|
@objc private func updateUserInfo() {
|
||||||
|
let userInfo = BRLoginManager.manager.userInfo
|
||||||
|
|
||||||
|
coinLabel.text = " \(userInfo?.totalCoin ?? 0)"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -10,6 +10,8 @@ import UIKit
|
|||||||
|
|
||||||
@objc protocol BRPlayerViewModelDelegate {
|
@objc protocol BRPlayerViewModelDelegate {
|
||||||
|
|
||||||
|
@objc func br_playProgressDidChange(viewModel: BRPlayerViewModel, time: TimeInterval)
|
||||||
|
|
||||||
@objc func br_currentVideoPlayFinish(viewModel: BRPlayerViewModel)
|
@objc func br_currentVideoPlayFinish(viewModel: BRPlayerViewModel)
|
||||||
|
|
||||||
@objc func br_switchPlayAndPause(viewModel: BRPlayerViewModel)
|
@objc func br_switchPlayAndPause(viewModel: BRPlayerViewModel)
|
||||||
@ -17,6 +19,9 @@ import UIKit
|
|||||||
@objc func br_onEpisodeView(viewModel: BRPlayerViewModel)
|
@objc func br_onEpisodeView(viewModel: BRPlayerViewModel)
|
||||||
|
|
||||||
@objc func br_clickRateButton(viewModel: BRPlayerViewModel)
|
@objc func br_clickRateButton(viewModel: BRPlayerViewModel)
|
||||||
|
|
||||||
|
@objc func br_needUpdateAllData(viewModel: BRPlayerViewModel, scrollTo indexPath: IndexPath?)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -24,6 +29,8 @@ class BRPlayerViewModel: NSObject {
|
|||||||
|
|
||||||
weak var delegate: BRPlayerViewModelDelegate?
|
weak var delegate: BRPlayerViewModelDelegate?
|
||||||
|
|
||||||
|
weak var playerListVC: BRPlayerListViewController?
|
||||||
|
|
||||||
@objc dynamic var isPlaying: Bool = true
|
@objc dynamic var isPlaying: Bool = true
|
||||||
|
|
||||||
var currentIndexPath = IndexPath(row: 0, section: 0)
|
var currentIndexPath = IndexPath(row: 0, section: 0)
|
||||||
@ -44,12 +51,22 @@ class BRPlayerViewModel: NSObject {
|
|||||||
self.currentPlayer?.rate = rateModel.rate.getRate()
|
self.currentPlayer?.rate = rateModel.rate.getRate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lazy var payDataRequest = VPPayDataRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extension BRPlayerViewModel {
|
extension BRPlayerViewModel {
|
||||||
|
|
||||||
|
///播放进度变更
|
||||||
|
func playProgressDidChange(time: TimeInterval) {
|
||||||
|
if time > 1 {
|
||||||
|
self.currentPlayer?.videoInfo?.play_seconds = Int(time) * 1000
|
||||||
|
}
|
||||||
|
self.delegate?.br_playProgressDidChange(viewModel: self, time: time)
|
||||||
|
}
|
||||||
|
|
||||||
func playFinish(player: BRPlayerProtocol) {
|
func playFinish(player: BRPlayerProtocol) {
|
||||||
guard (player as? UICollectionViewCell) == (currentPlayer as? UICollectionViewCell) else { return }
|
guard (player as? UICollectionViewCell) == (currentPlayer as? UICollectionViewCell) else { return }
|
||||||
self.delegate?.br_currentVideoPlayFinish(viewModel: self)
|
self.delegate?.br_currentVideoPlayFinish(viewModel: self)
|
||||||
@ -73,7 +90,106 @@ extension BRPlayerViewModel {
|
|||||||
///设置进度
|
///设置进度
|
||||||
func seekTo(progress: Float) {
|
func seekTo(progress: Float) {
|
||||||
self.currentPlayer?.seekTo(progress: progress)
|
self.currentPlayer?.seekTo(progress: progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
///点击解锁按钮
|
||||||
|
func clickUnlockButton() {
|
||||||
|
unlockVideo { [weak self] finish in
|
||||||
|
if finish {
|
||||||
|
self?.playerListVC?.reloadData {
|
||||||
|
self?.playerListVC?.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///更新全部数据
|
||||||
|
func updateAllData(scrollTo indexPath: IndexPath? = nil) {
|
||||||
|
|
||||||
|
self.delegate?.br_needUpdateAllData(viewModel: self, scrollTo: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension BRPlayerViewModel {
|
||||||
|
func unlockVideo(completer: ((_ finish: Bool) -> Void)?) {
|
||||||
|
let videoInfo = self.currentPlayer?.videoInfo
|
||||||
|
guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return }
|
||||||
|
|
||||||
|
BRVideoAPI.requestCoinUnlockVideo(shortPlayId: shortPlayId, videoId: videoId) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else {
|
||||||
|
completer?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch model.status {
|
||||||
|
case .jump:
|
||||||
|
BRToast.show(text: "beereel_jump_unlock_error".localized)
|
||||||
|
completer?(false)
|
||||||
|
|
||||||
|
case .noPlay:
|
||||||
|
BRToast.show(text: "beereel_buy_fail_toast_01".localized)
|
||||||
|
completer?(false)
|
||||||
|
|
||||||
|
case .notEnough:
|
||||||
|
self.openRechargeView()
|
||||||
|
completer?(false)
|
||||||
|
|
||||||
|
case .success:
|
||||||
|
//更新用户信息
|
||||||
|
BRLoginManager.manager.updateUserInfo {
|
||||||
|
videoInfo?.is_lock = false
|
||||||
|
completer?(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
completer?(false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///打开充值页面
|
||||||
|
func openRechargeView() {
|
||||||
|
guard let videoInfo = self.currentPlayer?.videoInfo else { return }
|
||||||
|
|
||||||
|
self.payDataRequest.requestProducts(isLoding: true) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
let view = BRVideoRechargeView()
|
||||||
|
view.shortPlayId = videoInfo.short_play_id
|
||||||
|
view.videoId = videoInfo.short_play_video_id
|
||||||
|
view.payDataModel = model
|
||||||
|
view.unlockCoin = self.currentPlayer?.videoInfo?.coins
|
||||||
|
view.buyVipFinishBlock = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.updateAllData(scrollTo: self.currentIndexPath)
|
||||||
|
}
|
||||||
|
view.buyCoinsFinishBlock = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.updateAllData(scrollTo: self.currentIndexPath)
|
||||||
|
}
|
||||||
|
view.present(in: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///上报播放进度
|
||||||
|
func uploadPlayTime() {
|
||||||
|
let videoInfo = self.currentPlayer?.videoInfo
|
||||||
|
let currentTime = self.currentPlayer?.currentTime ?? 0
|
||||||
|
let duration = self.currentPlayer?.durationTime ?? 0
|
||||||
|
|
||||||
|
var time = currentTime
|
||||||
|
if currentTime >= duration {
|
||||||
|
time = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return }
|
||||||
|
|
||||||
|
//上报播放时长
|
||||||
|
BRVideoAPI.requestUploadPlayTime(shortPlayId: shortPlayId, videoId: videoId, seconds: Int(time) * 1000)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,6 +11,8 @@ class BRStoreViewController: BRViewController {
|
|||||||
|
|
||||||
private var payData: BRPayDateModel?
|
private var payData: BRPayDateModel?
|
||||||
|
|
||||||
|
private lazy var dataRequest = VPPayDataRequest()
|
||||||
|
|
||||||
private lazy var scrollView: BRScrollView = {
|
private lazy var scrollView: BRScrollView = {
|
||||||
let scrollView = BRScrollView()
|
let scrollView = BRScrollView()
|
||||||
return scrollView
|
return scrollView
|
||||||
@ -95,8 +97,7 @@ extension BRStoreViewController {
|
|||||||
extension BRStoreViewController {
|
extension BRStoreViewController {
|
||||||
|
|
||||||
private func requestPayData() {
|
private func requestPayData() {
|
||||||
|
self.dataRequest.requestProducts { [weak self] model in
|
||||||
BRStoreAPI.requestPayTemplate { [weak self] model in
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
guard let model = model else { return }
|
guard let model = model else { return }
|
||||||
|
|
||||||
@ -123,7 +124,6 @@ extension BRStoreViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.stackView.addArrangedSubview(self.tipView)
|
self.stackView.addArrangedSubview(self.tipView)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
114
BeeReel/Class/Store/Model/VPPayDataRequest.swift
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
//
|
||||||
|
// VPPayDataRequest.swift
|
||||||
|
// BeeReel
|
||||||
|
//
|
||||||
|
// Created by 长沙鸿瑶 on 2025/7/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import StoreKit
|
||||||
|
|
||||||
|
class VPPayDataRequest: NSObject {
|
||||||
|
|
||||||
|
private var oldTemplateModel: BRPayDateModel?
|
||||||
|
|
||||||
|
private var completerBlock: ((_ model: BRPayDateModel?) -> Void)?
|
||||||
|
|
||||||
|
private var isLoding = false
|
||||||
|
private var isToast = false
|
||||||
|
|
||||||
|
|
||||||
|
func requestProducts(isLoding: Bool = false, isToast: Bool = true, completer: ((_ model: BRPayDateModel?) -> Void)?) {
|
||||||
|
self.completerBlock = completer
|
||||||
|
self.isLoding = isLoding
|
||||||
|
self.isToast = isToast
|
||||||
|
|
||||||
|
if isLoding {
|
||||||
|
BRHUD.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
BRStoreAPI.requestPayTemplate { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if isLoding {
|
||||||
|
BRHUD.dismiss()
|
||||||
|
}
|
||||||
|
completer?(model)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// BRStoreAPI.requestPayTemplate(isToast: isToast) { [weak self] model in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// guard let model = model else {
|
||||||
|
// if isLoding {
|
||||||
|
// VPHUD.dismiss()
|
||||||
|
// }
|
||||||
|
// self.completerBlock?(nil)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// self.oldTemplateModel = model
|
||||||
|
//
|
||||||
|
// var productIdArr: [String] = []
|
||||||
|
// model.list_sub_vip?.forEach { item in
|
||||||
|
// productIdArr.append(VPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||||
|
// }
|
||||||
|
// model.list_coins?.forEach { item in
|
||||||
|
// productIdArr.append(VPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// let set = Set(productIdArr)
|
||||||
|
// let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||||
|
// productsRequest.delegate = self
|
||||||
|
// productsRequest.start()
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//MARK: -------------- SKProductsRequestDelegate --------------
|
||||||
|
extension VPPayTemplateRequest: SKProductsRequestDelegate {
|
||||||
|
|
||||||
|
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||||
|
if isLoding {
|
||||||
|
VPHUD.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let templateModel = self.oldTemplateModel else { return }
|
||||||
|
let products = response.products
|
||||||
|
|
||||||
|
var newCoinList: [VPPayTemplateItem] = []
|
||||||
|
var newVipList: [VPPayTemplateItem] = []
|
||||||
|
|
||||||
|
templateModel.list_coins?.forEach { item in
|
||||||
|
let productId = VPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||||
|
for product in products {
|
||||||
|
if productId == product.productIdentifier {
|
||||||
|
item.price = product.price.stringValue
|
||||||
|
item.currency = product.priceLocale.currencySymbol
|
||||||
|
newCoinList.append(item)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templateModel.list_sub_vip?.forEach { item in
|
||||||
|
let productId = VPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||||
|
for product in products {
|
||||||
|
if productId == product.productIdentifier {
|
||||||
|
item.price = product.price.stringValue
|
||||||
|
item.currency = product.priceLocale.currencySymbol
|
||||||
|
newVipList.append(item)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templateModel.list_coins = newCoinList
|
||||||
|
templateModel.list_sub_vip = newVipList
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.completerBlock?(templateModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
@ -9,6 +9,8 @@ import UIKit
|
|||||||
|
|
||||||
class BRStoreCoinView: UIView {
|
class BRStoreCoinView: UIView {
|
||||||
|
|
||||||
|
var buyFinishBlock: (() -> Void)?
|
||||||
|
|
||||||
var list: [BRPayItem] = [] {
|
var list: [BRPayItem] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
|
|
||||||
@ -30,6 +32,9 @@ class BRStoreCoinView: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
private var newList: [[BRPayItem]] = []
|
private var newList: [[BRPayItem]] = []
|
||||||
|
|
||||||
private lazy var titleLabel: UILabel = {
|
private lazy var titleLabel: UILabel = {
|
||||||
|
@ -9,12 +9,17 @@ import UIKit
|
|||||||
|
|
||||||
class BRStoreVipView: UIView {
|
class BRStoreVipView: UIView {
|
||||||
|
|
||||||
|
var buyFinishBlock: (() -> Void)?
|
||||||
|
|
||||||
var list: [BRPayItem] = [] {
|
var list: [BRPayItem] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
self.collectionView.reloadData()
|
self.collectionView.reloadData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
private lazy var titleLabel: UILabel = {
|
private lazy var titleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.textColor = .colorFFFFFF()
|
label.textColor = .colorFFFFFF()
|
||||||
|
@ -10,6 +10,8 @@ import SJBaseVideoPlayer
|
|||||||
|
|
||||||
|
|
||||||
@objc protocol BRPlayerDelegate: NSObjectProtocol {
|
@objc protocol BRPlayerDelegate: NSObjectProtocol {
|
||||||
|
|
||||||
|
@objc optional func br_playerReadyToPlay(_ player: BRPlayer)
|
||||||
///更新当前总进度
|
///更新当前总进度
|
||||||
@objc optional func br_playerDurationDidChange(_ player: BRPlayer, duration: TimeInterval)
|
@objc optional func br_playerDurationDidChange(_ player: BRPlayer, duration: TimeInterval)
|
||||||
///更新当前进度
|
///更新当前进度
|
||||||
@ -150,8 +152,6 @@ extension BRPlayer {
|
|||||||
//播放控制改变的回调
|
//播放控制改变的回调
|
||||||
self.player.playbackObserver.timeControlStatusDidChangeExeBlock = { [weak self] player in
|
self.player.playbackObserver.timeControlStatusDidChangeExeBlock = { [weak self] player in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
// , player.reasonForWaitingToPlay == SJWaitingToMinimizeStallsReason
|
|
||||||
|
|
||||||
if player.timeControlStatus == .waitingToPlay {//缓冲中
|
if player.timeControlStatus == .waitingToPlay {//缓冲中
|
||||||
self.delegate?.br_playerInBufferToPlay?(self)
|
self.delegate?.br_playerInBufferToPlay?(self)
|
||||||
brLog(message: "=======缓冲中 === \(player.reasonForWaitingToPlay ?? "")")
|
brLog(message: "=======缓冲中 === \(player.reasonForWaitingToPlay ?? "")")
|
||||||
@ -161,6 +161,14 @@ extension BRPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.player.playbackObserver.assetStatusDidChangeExeBlock = { [weak self] player in
|
||||||
|
guard let self = self else { return }
|
||||||
|
brLog(message: "assetStatus === \(player.assetStatus.rawValue)")
|
||||||
|
if player.assetStatus == .readyToPlay {
|
||||||
|
self.delegate?.br_playerReadyToPlay?(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//播放时长改变
|
//播放时长改变
|
||||||
self.player.playbackObserver.durationDidChangeExeBlock = { [weak self] player in
|
self.player.playbackObserver.durationDidChangeExeBlock = { [weak self] player in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
22
BeeReel/Sources/Assets.xcassets/icon/Frame 3.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
BeeReel/Sources/Assets.xcassets/icon/Frame 3.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 375 B |
BIN
BeeReel/Sources/Assets.xcassets/icon/Frame 3.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 487 B |
22
BeeReel/Sources/Assets.xcassets/icon/Frame 4.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
BeeReel/Sources/Assets.xcassets/icon/Frame 4.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
BeeReel/Sources/Assets.xcassets/icon/Frame 4.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.3 KiB |
22
BeeReel/Sources/Assets.xcassets/icon/Frame 5.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
BeeReel/Sources/Assets.xcassets/icon/Frame 5.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 757 B |
BIN
BeeReel/Sources/Assets.xcassets/icon/Frame 5.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 1.0 KiB |
22
BeeReel/Sources/Assets.xcassets/icon/Frame 6.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
BeeReel/Sources/Assets.xcassets/icon/Frame 6.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
BeeReel/Sources/Assets.xcassets/icon/Frame 6.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.3 KiB |
22
BeeReel/Sources/Assets.xcassets/icon/bg 1.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "bg@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "bg@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
BeeReel/Sources/Assets.xcassets/icon/bg 1.imageset/bg@2x.png
vendored
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
BeeReel/Sources/Assets.xcassets/icon/bg 1.imageset/bg@3x.png
vendored
Normal file
After Width: | Height: | Size: 36 KiB |
22
BeeReel/Sources/Assets.xcassets/icon/bg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "bg@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "bg@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
BeeReel/Sources/Assets.xcassets/icon/bg.imageset/bg@2x.png
vendored
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
BeeReel/Sources/Assets.xcassets/icon/bg.imageset/bg@3x.png
vendored
Normal file
After Width: | Height: | Size: 93 KiB |
@ -34,6 +34,41 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Balance: ## Coins" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Balance: ## Coins"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"beereel_buy_fail_toast_01" : {
|
||||||
|
"comment" : "解锁失败提示",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Purchase failed, please try again later!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"beereel_jump_unlock_error" : {
|
||||||
|
"comment" : "解锁上一集提示",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"beereel_network" : {
|
"beereel_network" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -320,6 +355,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"My Coins:" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "My Coins:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"New Releases" : {
|
"New Releases" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -474,6 +520,39 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Unlock to Continue" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Unlock to Continue"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Unlock:" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Unlock:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Unlocking costs ## Coins" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Unlocking costs ## Coins"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"User Agreement" : {
|
"User Agreement" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|