diff --git a/MoviaBox.xcodeproj/project.pbxproj b/MoviaBox.xcodeproj/project.pbxproj index 4e2194e..f1dbaa2 100644 --- a/MoviaBox.xcodeproj/project.pbxproj +++ b/MoviaBox.xcodeproj/project.pbxproj @@ -235,7 +235,7 @@ CODE_SIGN_ENTITLEMENTS = MoviaBox/MoviaBox.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = TWDZ3MP9DV; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -257,7 +257,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.2; PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -281,7 +281,7 @@ CODE_SIGN_ENTITLEMENTS = MoviaBox/MoviaBox.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = TWDZ3MP9DV; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -303,7 +303,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.2; PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/MoviaBox/Base/Extension/UIColor+SPAdd.swift b/MoviaBox/Base/Extension/UIColor+SPAdd.swift index d07bc21..e4fee53 100644 --- a/MoviaBox/Base/Extension/UIColor+SPAdd.swift +++ b/MoviaBox/Base/Extension/UIColor+SPAdd.swift @@ -408,5 +408,13 @@ extension UIColor { static func colorFF473D(alpha: CGFloat = 1) -> UIColor { return color(hex: 0xFF473D, alpha: alpha) } + + static func color622100(alpha: CGFloat = 1) -> UIColor { + return color(hex: 0x622100, alpha: alpha) + } + + static func colorFFC555(alpha: CGFloat = 1) -> UIColor { + return color(hex: 0xFFC555, alpha: alpha) + } } diff --git a/MoviaBox/Base/Networking/API/SPVideoAPI.swift b/MoviaBox/Base/Networking/API/SPVideoAPI.swift index 11f3c41..03bcc49 100644 --- a/MoviaBox/Base/Networking/API/SPVideoAPI.swift +++ b/MoviaBox/Base/Networking/API/SPVideoAPI.swift @@ -32,12 +32,12 @@ class SPVideoAPI: NSObject { } ///创建播放记录 - static func requestCreateVideoPlayHistory(videoId: String, shortPlayId: String) { + static func requestCreateVideoPlayHistory(videoId: String?, shortPlayId: String) { var param = SPNetworkParameters(path: "/createHistory") param.isLoding = false param.isToast = false param.parameters = [ - "video_id" : videoId, + "video_id" : videoId ?? "0", "short_play_id" : shortPlayId ] @@ -165,6 +165,17 @@ class SPVideoAPI: NSObject { completer?(response.data) } } + + ///视频推荐 + static func requestPlayerDetailsRecommand(completer: ((_ list: [SPShortModel]?) -> Void)?) { + + var param = SPNetworkParameters(path: "/getDetailsRecommand") + param.method = .get + + SPNetwork.request(parameters: param) { (response: SPNetworkResponse>) in + completer?(response.data?.list) + } + } } extension SPVideoAPI { diff --git a/MoviaBox/Class/Mine/Controller/SPMineViewController.swift b/MoviaBox/Class/Mine/Controller/SPMineViewController.swift index d4970bd..41abbf7 100644 --- a/MoviaBox/Class/Mine/Controller/SPMineViewController.swift +++ b/MoviaBox/Class/Mine/Controller/SPMineViewController.swift @@ -11,7 +11,7 @@ class SPMineViewController: SPViewController { private lazy var dataArr: [SPMineItem] = { let arr = [ - SPMineItem(type: .language, iconImage: UIImage(named: "language_icon_01"), title: "movia_profile_Language".localized), +// SPMineItem(type: .language, iconImage: UIImage(named: "language_icon_01"), title: "movia_profile_Language".localized), SPMineItem(type: .feedBack, iconImage: UIImage(named: "feed_back_icon_01"), title: "movia_profile_Feedback".localized), SPMineItem(type: .privacyPolicy, iconImage: UIImage(named: "privacy_policy_icon_01"), title: "movia_profile_Privacy_Policy".localized), SPMineItem(type: .userAgreement, iconImage: UIImage(named: "user_agreement_icon_01"), title: "movia_profile_User_Agreement".localized), diff --git a/MoviaBox/Class/Player/Controller/SPPlayerDetailViewController.swift b/MoviaBox/Class/Player/Controller/SPPlayerDetailViewController.swift index 8771ee7..5b83d37 100644 --- a/MoviaBox/Class/Player/Controller/SPPlayerDetailViewController.swift +++ b/MoviaBox/Class/Player/Controller/SPPlayerDetailViewController.swift @@ -28,6 +28,10 @@ class SPPlayerDetailViewController: SPPlayerListViewController { ///上一次上报播放时长的节点 private var lastUploadTime: Int = 0 + ///是否展示推荐数据 + private var isShowRecommand = false + private var recommandTimer: Timer? + //MARK: UI属性 ///选集视图 private weak var episodeView: SPEpisodeView? @@ -135,8 +139,35 @@ class SPPlayerDetailViewController: SPPlayerListViewController { // uploadPlayTime() // } } + /* + override func handleBack() { + guard isShowRecommand else { + super.handleBack() + return + } + + self.pause() + let view = SPPlayerDetailRecommandView() + view.clickCloseButton = { [weak self] in + guard let self = self else { return } + self._handleBack() + } + + view.clickPlayButton = { [weak self] model in + guard let self = self else { return } + self.shortPlayId = model.short_play_id + self.activityId = nil + self.videoId = nil + self.requestDetailData() + } + view.present(in: nil) + } - + + private func _handleBack() { + super.handleBack() + } + */ } extension SPPlayerDetailViewController { @@ -276,6 +307,10 @@ extension SPPlayerDetailViewController { } } + @objc private func handleRecommandTimer() { + self.isShowRecommand = true + } + } //MARK: -------------- SPPlayerListViewControllerDataSource -------------- @@ -330,6 +365,10 @@ extension SPPlayerDetailViewController { private func requestDetailData() { guard let shortPlayId = self.shortPlayId else { return } + isShowRecommand = false + recommandTimer?.invalidate() + recommandTimer = nil + recommandTimer = Timer.scheduledTimer(timeInterval: 6, target: YYWeakProxy(target: self), selector: #selector(handleRecommandTimer), userInfo: nil, repeats: false) SPVideoAPI.requestVideoDetail(videoId: videoId, shortPlayId: shortPlayId, activityId: activityId) { [weak self] model in guard let self = self else { return } @@ -352,11 +391,17 @@ extension SPPlayerDetailViewController { self.viewModel.currentPlayer?.seekToTime(toTime: (videoInfo.play_seconds ?? 0) / 1000) } } else { - self.play() + self.scrollToItem(indexPath: .init(row: 0, section: 0), animated: false) { [weak self] in + guard let self = self else { return } + self.play() + } } } else { - self.play() + self.scrollToItem(indexPath: .init(row: 0, section: 0), animated: false) { [weak self] in + guard let self = self else { return } + self.play() + } } } diff --git a/MoviaBox/Class/Player/Controller/SPPlayerListViewController.swift b/MoviaBox/Class/Player/Controller/SPPlayerListViewController.swift index 2d37fde..4e100ff 100644 --- a/MoviaBox/Class/Player/Controller/SPPlayerListViewController.swift +++ b/MoviaBox/Class/Player/Controller/SPPlayerListViewController.swift @@ -90,7 +90,7 @@ class SPPlayerListViewController: SPViewController { override func viewDidLoad() { super.viewDidLoad() - + self.jx_popGestureType = .disabled //视频缓存 do { try? KTVHTTPCache.proxyStart() diff --git a/MoviaBox/Class/Player/View/SPPlayerDetailRecommandCell.swift b/MoviaBox/Class/Player/View/SPPlayerDetailRecommandCell.swift new file mode 100644 index 0000000..75ba72e --- /dev/null +++ b/MoviaBox/Class/Player/View/SPPlayerDetailRecommandCell.swift @@ -0,0 +1,47 @@ +// +// SPPlayerDetailRecommandCell.swift +// MoviaBox +// +// Created by 佳尔 on 2025/5/12. +// + +import UIKit + +class SPPlayerDetailRecommandCell: ZKCycleScrollViewCell { + + var model: SPShortModel? { + didSet { + coverImageView.sp_setImage(url: model?.image_url) + } + } + + private lazy var coverImageView: SPImageView = { + let imageView = SPImageView() + imageView.layer.cornerRadius = 6 + imageView.layer.masksToBounds = true + return imageView + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + _setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension SPPlayerDetailRecommandCell { + private func _setupUI() { + contentView.addSubview(coverImageView) + + coverImageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + + +} diff --git a/MoviaBox/Class/Player/View/SPPlayerDetailRecommandView.swift b/MoviaBox/Class/Player/View/SPPlayerDetailRecommandView.swift new file mode 100644 index 0000000..8ce4b71 --- /dev/null +++ b/MoviaBox/Class/Player/View/SPPlayerDetailRecommandView.swift @@ -0,0 +1,213 @@ +// +// SPPlayerDetailRecommandView.swift +// MoviaBox +// +// Created by 佳尔 on 2025/5/12. +// + +import UIKit + +class SPPlayerDetailRecommandView: HWPanModalContentView { + + private lazy var dataArr: [SPShortModel] = [] + + var clickCloseButton: (() -> Void)? + var clickPlayButton: ((_ model: SPShortModel) -> Void)? + + //MARK: UI属性 + private lazy var bgImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "recommand_bg_image_01")) + return imageView + }() + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 20) + label.textColor = .colorFFFFFF() + label.text = "movia_top_today".localized + return label + }() + + 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 bannerView: ZKCycleScrollView = { + let view = ZKCycleScrollView(frame: .zero, shouldInfiniteLoop: true) + view.delegate = self + view.dataSource = self + view.itemSize = CGSize(width: 231, height: 322) + view.itemZoomScale = 0.8 + view.itemSpacing = 0 + view.register(SPPlayerDetailRecommandCell.self, forCellWithReuseIdentifier: "cell") + view.hidesPageControl = true + return view + }() + + private lazy var videoNameLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 18) + label.textColor = .colorFFFFFF(alpha: 0.8) + label.textAlignment = .center + label.numberOfLines = 2 + return label + }() + + private lazy var playButton: UIButton = { + let button = UIButton(type: .custom) + button.setTitle("movia_play_now".localized, for: .normal) + button.setTitleColor(.color622100(), for: .normal) + button.titleLabel?.font = .fontMedium(ofSize: 18) + button.layer.cornerRadius = 8 + button.layer.masksToBounds = true + button.setBackgroundImage(UIImage(color: .colorFFC555()), for: .normal) + button.addTarget(self, action: #selector(handlePlayButton), for: .touchUpInside) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + _setupUI() + + requestDataArr() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //MARK: HWPanModalPresentable + override func longFormHeight() -> PanModalHeight { + return PanModalHeightMake(.content, 540) + } + + override func showDragIndicator() -> Bool { + return false + } + + override func backgroundConfig() -> HWBackgroundConfig { + let config = HWBackgroundConfig() + config.backgroundAlpha = 0.6 + return config + } + + override func allowsTapBackgroundToDismiss() -> Bool { + return false + } + + override func allowsDragToDismiss() -> Bool { + return false + } + + override func allowsPullDownWhenShortState() -> Bool { + return false + } +} + +extension SPPlayerDetailRecommandView { + + @objc private func handleCloseButton() { + self.dismiss(animated: true) { + } + self.clickCloseButton?() + } + + @objc private func handlePlayButton() { + guard self.dataArr.count > 0 else { + return + } + self.dismiss(animated: true) { + } + + let model = self.dataArr[bannerView.currentIdx] + self.clickPlayButton?(model) + } + +} + +extension SPPlayerDetailRecommandView { + private func _setupUI() { + addSubview(bgImageView) + addSubview(titleLabel) + addSubview(closeButton) + addSubview(bannerView) + addSubview(videoNameLabel) + addSubview(playButton) + + bgImageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(27) + } + + closeButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-16) + make.centerY.equalTo(titleLabel) + } + + bannerView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().offset(78) + make.height.equalTo(322) + } + + videoNameLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(bannerView.snp.bottom).offset(15) + make.width.lessThanOrEqualTo(260) + } + + playButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.centerX.equalToSuperview() + make.top.equalTo(bannerView.snp.bottom).offset(81) + make.height.equalTo(46) + } + } + +} + +//MARK: -------------- ZKCycleScrollViewDelegate & ZKCycleScrollViewDataSource -------------- +extension SPPlayerDetailRecommandView: ZKCycleScrollViewDelegate, ZKCycleScrollViewDataSource { + func numberOfItems(in cycleScrollView: ZKCycleScrollView) -> Int { + return self.dataArr.count + } + + func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, cellForItemAt index: Int) -> ZKCycleScrollViewCell { + let cell = cycleScrollView.dequeueReusableCell(withReuseIdentifier: "cell", for: index) as! SPPlayerDetailRecommandCell + cell.model = self.dataArr[index] + return cell + } + + + func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, didScrollFromIndex fromIndex: Int, toIndex: Int) { + let model = self.dataArr[toIndex] + videoNameLabel.text = model.name + + } + +} + +extension SPPlayerDetailRecommandView { + + private func requestDataArr() { + SPVideoAPI.requestPlayerDetailsRecommand { [weak self] list in + guard let self = self else { return } + if let list = list { + self.dataArr = list + let model = self.dataArr.first + self.videoNameLabel.text = model?.name + + self.bannerView.reloadData() + } + } + } + +} diff --git a/MoviaBox/Class/Wallet/View/SPMemberRechargeView.swift b/MoviaBox/Class/Wallet/View/SPMemberRechargeView.swift index 3635723..f535944 100644 --- a/MoviaBox/Class/Wallet/View/SPMemberRechargeView.swift +++ b/MoviaBox/Class/Wallet/View/SPMemberRechargeView.swift @@ -63,13 +63,13 @@ class SPMemberRechargeView: UIView { ///设置数据 func setDataArr(dataArr: [SPPayTemplateItem]?) { - self.dataArr = [] + self.dataArr = dataArr - dataArr?.forEach({ - if $0.vip_type_key == .quarter { - self.dataArr?.append($0) - } - }) +// dataArr?.forEach({ +// if $0.vip_type_key == .quarter { +// self.dataArr?.append($0) +// } +// }) self.collectionView.reloadData() self.invalidateIntrinsicContentSize() } diff --git a/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Contents.json b/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Contents.json new file mode 100644 index 0000000..8abf372 --- /dev/null +++ b/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 185@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 185@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Frame 185@2x.png b/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Frame 185@2x.png new file mode 100644 index 0000000..9a2e768 Binary files /dev/null and b/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Frame 185@2x.png differ diff --git a/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Frame 185@3x.png b/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Frame 185@3x.png new file mode 100644 index 0000000..59fb86b Binary files /dev/null and b/MoviaBox/Source/Assets.xcassets/icon/close_icon_01.imageset/Frame 185@3x.png differ diff --git a/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/Contents.json b/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/Contents.json new file mode 100644 index 0000000..708fa3c --- /dev/null +++ b/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "渐变背景@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "渐变背景@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/渐变背景@2x.png b/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/渐变背景@2x.png new file mode 100644 index 0000000..d123ded Binary files /dev/null and b/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/渐变背景@2x.png differ diff --git a/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/渐变背景@3x.png b/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/渐变背景@3x.png new file mode 100644 index 0000000..e6621f7 Binary files /dev/null and b/MoviaBox/Source/Assets.xcassets/image/recommand_bg_image_01.imageset/渐变背景@3x.png differ diff --git a/MoviaBox/Source/en.lproj/Localizable.strings b/MoviaBox/Source/en.lproj/Localizable.strings index 1553200..bcf37cb 100644 --- a/MoviaBox/Source/en.lproj/Localizable.strings +++ b/MoviaBox/Source/en.lproj/Localizable.strings @@ -99,6 +99,8 @@ "movia_profile_Coins" = "Coins"; "movia_open_notification" = "Enable Notifications"; "movia_open_notification_info" = "Stay informed with popular recommendations and latest updates!"; +"movia_top_today" = "Top Today"; +"movia_play_now" = "Play Now"; "movia_iap_error_toast_01" = "Invalid in-app purchase";