// // MPPositive_PersonalisedRecommendationsTableViewCell.swift // relax.offline.mp3.music // // Created by Mr.Zhou on 2024/8/28. // import UIKit import Lottie class MPPositive_PersonalisedRecommendationsTableViewCell: UITableViewCell, UIViewControllerTransitioningDelegate { ///主标题(因为你听过/因为你喜欢) private lazy var titleLabel:UILabel = createLabel(font: .systemFont(ofSize: 14*width), textColor: .init(hex: "#FFFFFF", alpha: 0.6), textAlignment: .left) ///副标题(随机项的内容值) private lazy var subTitleLabel:UILabel = { let label = createLabel(font: .systemFont(ofSize: 16*width, weight: .bold), textColor: .white, textAlignment: .left) label.isUserInteractionEnabled = true label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(findRecommonedEvent(_ :)))) return label }() ///刷新Icon private lazy var reloadlotView:LottieAnimationView = { //获取动画View let json = Bundle.main.path(forResource: "Reload_Animation", ofType: "json") let animationView:LottieAnimationView = .init(filePath: json ?? "") //无限循环 animationView.loopMode = .loop //填充 animationView.contentMode = .scaleAspectFill animationView.backgroundColor = .clear return animationView }() ///个性化布局类型 enum PersonlShowType:Int { case Singles = 0 case Lists = 1 case Artists = 2 ///对应布局layout var layout:UICollectionViewFlowLayout { let layout = UICollectionViewFlowLayout() switch self { case .Singles: layout.itemSize = .init(width: screen_Width*0.85, height: 70*width) layout.sectionInset = .init(top: 10*width, left: 16*width, bottom: 0, right: 16*width) layout.minimumLineSpacing = 0 layout.minimumInteritemSpacing = 0 layout.scrollDirection = .horizontal case .Lists: layout.sectionInset = .init(top: 15*width, left: 16*width, bottom: 0, right: 16*width) layout.minimumLineSpacing = 8*width layout.itemSize = .init(width: 109*width, height: 152*width) layout.minimumInteritemSpacing = 0 layout.scrollDirection = .horizontal case .Artists: layout.sectionInset = .init(top: 15*width, left: 16*width, bottom: 0, right: 16*width) layout.minimumLineSpacing = 8*width layout.itemSize = .init(width: 94*width, height: 116*width) layout.minimumInteritemSpacing = 0 layout.scrollDirection = .horizontal } return layout } } //展示collectionView private lazy var collectionView:UICollectionView = { let collectionView:UICollectionView = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: screen_Height), collectionViewLayout: showType.layout) collectionView.showsVerticalScrollIndicator = false collectionView.showsHorizontalScrollIndicator = false collectionView.backgroundColor = .clear collectionView.dataSource = self collectionView.delegate = self collectionView.register(MPPositive_HomeSingleCollectionViewCell.self, forCellWithReuseIdentifier: MPPositive_HomeSingleCollectionViewCellID) collectionView.register(MPPositive_HomeListThirdCollectionViewCell.self, forCellWithReuseIdentifier: MPPositive_HomeListThirdCollectionViewCellID) collectionView.register(MPPositive_HomeListFourthCollectionViewCell.self, forCellWithReuseIdentifier: MPPositive_HomeListFourthCollectionViewCellID) return collectionView }() private let MPPositive_HomeSingleCollectionViewCellID = "MPPositive_HomeSingleCollectionViewCell" private let MPPositive_HomeListThirdCollectionViewCellID = "MPPositive_HomeListThirdCollectionViewCell" private let MPPositive_HomeListFourthCollectionViewCellID = "MPPositive_HomeListFourthCollectionViewCell" var personlViewModel:MPPositive_PersonalListViewModel?{ didSet{ titleLabel.text = personlViewModel?.title subTitleLabel.text = titleLabel.text == "Because you listen".localizableString() ? personlViewModel?.random?.title:personlViewModel?.random?.subtitle reloadlotView.stop() if let first = personlViewModel?.items.first, first.browseItem.itemType == .single { showType = .Singles }else { //判断是列表还是艺术家 if personlViewModel?.items.first?.browseItem.pageType == "MUSIC_PAGE_TYPE_ARTIST" { showType = .Artists }else { showType = .Lists } } } } var reloadRecommondBlock:((Int) -> Void)? ///列表展示类型 var showType:PersonlShowType = .Singles{ didSet{ collectionView.collectionViewLayout = showType.layout collectionView.reloadData() collectionView.scrollToItem(at: .init(row: 0, section: 0), at: .top, animated: false) } } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) confirgue() } required init?(coder: NSCoder) { super.init(coder: coder) } override func awakeFromNib() { super.awakeFromNib() // Initialization code } //配置 private func confirgue() { selectionStyle = .none backgroundColor = .clear contentView.backgroundColor = .clear //配置UI contentView.addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.left.equalToSuperview().offset(16*width) make.top.equalTo(8*width) } contentView.addSubview(subTitleLabel) subTitleLabel.snp.makeConstraints { make in make.left.equalTo(titleLabel) make.top.equalTo(titleLabel.snp.bottom).offset(6*width) make.width.equalToSuperview().multipliedBy(0.6) } let reloadView = createReloadView() contentView.addSubview(reloadView) reloadView.snp.makeConstraints { make in make.top.equalToSuperview().offset(10*width) make.right.equalToSuperview().offset(-16*width) make.width.equalTo(85*width) make.height.equalTo(35*width) } contentView.addSubview(collectionView) collectionView.snp.makeConstraints { make in make.top.equalTo(subTitleLabel.snp.bottom).offset(5*width) make.left.right.equalToSuperview() make.bottom.equalToSuperview().offset(-30*width) } } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } //生成一个刷新按钮View private func createReloadView() -> UIView { let view:UIView = .init(frame: .init(x: 0, y: 0, width: 60*width, height: 32*width)) view.backgroundColor = .init(hex: "#FFFFFF", alpha: 0.1) view.layer.masksToBounds = true view.layer.cornerRadius = 8*width view.addSubview(reloadlotView) reloadlotView.snp.makeConstraints { make in make.width.height.equalTo(20*width) make.centerY.equalToSuperview() make.left.equalToSuperview().offset(10*width) } reloadlotView.stop() //生成一个Label let label = createLabel("Refresh", font: .systemFont(ofSize: 12*width), textColor: .white, textAlignment: .center) view.addSubview(label) label.snp.makeConstraints { make in make.centerY.equalToSuperview() make.left.equalTo(reloadlotView.snp.right).offset(4*width) } view.isUserInteractionEnabled = true view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(reloadRecommonedEvent(_ :)))) return view } //刷新个性化模块 @objc private func reloadRecommonedEvent(_ sender:UITapGestureRecognizer) { reloadlotView.play() //刷新推荐信息 if titleLabel.text == "Because you listen".localizableString() { reloadRecommondBlock?(1) }else { reloadRecommondBlock?(2) } } //查看个性化内容 @objc private func findRecommonedEvent(_ sender:UITapGestureRecognizer) { guard let item = (self.personlViewModel?.random?.recently) else { return } switch showType { case.Singles: //单曲/视频跳转 MPPositive_Debouncer.shared.call { [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { playOfflineSongs() return } MP_AnalyticsManager.shared.home_b_module_clickAction(titleLabel.text ?? "") MP_AnalyticsManager.shared.song_clickAction("Home") //优先清除数据 MP_PlayerManager.shared.loadPlayer = nil //弹出播放器 NotificationCenter.notificationKey.post(notificationName: .pup_player_vc) MP_AnalyticsManager.shared.player_b_impAction() //触发next请求,优先获取列表全部单曲基础数据(不完善) MP_NetWorkManager.shared.requestNextList(item.playListID ?? "", videoId: item.videoId ?? "", clickTrackingParams: ""){ [weak self] listSongs in guard let self = self else {return} //回掉的数据并不完善,生成一个playerloadViewModel let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.videoId ?? "") lodaViewModel.improveData(item.videoId ?? "") //更改播放器播放类型 MP_PlayerManager.shared.setPlayType(.normal) MP_PlayerManager.shared.loadPlayer = lodaViewModel MP_AnalyticsManager.shared.player_b_listAction() } } default: //展示搜索内容 MP_AnalyticsManager.shared.search_from_actionAction("Home") let resultVC = MPPositive_SearchResultShowViewController(item.subtitle ?? "", isShowAd: true) self.parentController()?.navigationController?.pushViewController(resultVC, animated: false) } } //经过计算设置tableViewCell真实高度 override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { let size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority) collectionView.layoutIfNeeded() switch showType { case .Singles: let height = showType.layout.itemSize.height*3 + showType.layout.sectionInset.top + 10 return CGSize(width: size.width, height: size.height + height) default: let height = showType.layout.itemSize.height + showType.layout.sectionInset.top + showType.layout.sectionInset.bottom return CGSize(width: size.width, height: size.height + height) } } } //MARK: - collectionView extension MPPositive_PersonalisedRecommendationsTableViewCell:UICollectionViewDataSource, UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return personlViewModel?.items.count ?? 0 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { switch showType { case .Singles: let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MPPositive_HomeSingleCollectionViewCellID, for: indexPath) as! MPPositive_HomeSingleCollectionViewCell cell.itemViewModel = personlViewModel?.items[indexPath.row] cell.moreBlock = { [weak self] in guard let self = self, let itemView = (self.personlViewModel?.items[indexPath.row]) else {return} MPPositive_Debouncer.shared.call { MPPositive_ModalType = .MoreOperations let moreVC = MPPositive_MoreSongOperationsViewController(itemView) moreVC.disMissBlock = { DispatchQueue.main.async { collectionView.reloadData() } } moreVC.transitioningDelegate = self moreVC.modalPresentationStyle = .custom self.parentController()?.present(moreVC, animated: true) } } cell.deleteBlock = { [weak self] in guard let self = self else {return} //点击删除下载 let alertController = UIAlertController(title: "Delete This Song".localizableString(), message: "Are you sure you want to delete the offline resources of this song?".localizableString(), preferredStyle: .alert) let cancel = UIAlertAction(title: "Cancel".localizableString(), style: .cancel) alertController.addAction(cancel) let sure = UIAlertAction(title: "Confirm".localizableString(), style: .destructive) {(action) in guard let videoId = (self.personlViewModel?.items[indexPath.row].browseItem.videoId) else {return} //确定删除 MP_DownloadManager.shared.deleteFileDocuments(videoId) { videoId in MP_HUD.progress("Loading...".localizableString(), delay: 0.5) { MP_HUD.text("Removed".localizableString(), delay: 1.0, completion: nil) collectionView.reloadData() } } } alertController.addAction(sure) self.parentController()?.present(alertController, animated: true) } cell.cancelBlock = { [weak self] in guard let self = self else {return} //点击取消下载 let alertController = UIAlertController(title: "Cancel Song Download Task".localizableString(), message: "Are you sure you want to cancel the download task of this song?".localizableString(), preferredStyle: .alert) let cancel = UIAlertAction(title: "Cancel".localizableString(), style: .cancel) alertController.addAction(cancel) let sure = UIAlertAction(title: "Confirm".localizableString(), style: .destructive) {(action) in guard let videoId = (self.personlViewModel?.items[indexPath.row].browseItem.videoId) else {return} //确定取消 MP_DownloadManager.shared.cancelDownloadTask(videoId) { videoId in MP_HUD.text("Cancel".localizableString(), delay: 1.0, completion: nil) collectionView.reloadData() } } alertController.addAction(sure) self.parentController()?.present(alertController, animated: true) } return cell case .Lists: let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MPPositive_HomeListThirdCollectionViewCellID, for: indexPath) as! MPPositive_HomeListThirdCollectionViewCell cell.itemViewModel = personlViewModel?.items[indexPath.row] return cell default: let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MPPositive_HomeListFourthCollectionViewCellID, for: indexPath) as! MPPositive_HomeListFourthCollectionViewCell cell.itemViewModel = personlViewModel?.items[indexPath.row] return cell } } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { guard let item = (self.personlViewModel?.items[indexPath.row]) else { return } switch showType { case.Singles: //单曲/视频跳转 MPPositive_Debouncer.shared.call { [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { playOfflineSongs() return } MP_AnalyticsManager.shared.home_b_module_clickAction(item.browseItem.pageType ?? "") MP_AnalyticsManager.shared.song_clickAction("Home") //优先清除数据 MP_PlayerManager.shared.loadPlayer = nil //弹出播放器 NotificationCenter.notificationKey.post(notificationName: .pup_player_vc) MP_AnalyticsManager.shared.player_b_impAction() //触发next请求,优先获取列表全部单曲基础数据(不完善) MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams){ [weak self] listSongs in guard let self = self else {return} //回掉的数据并不完善,生成一个playerloadViewModel let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.browseItem.videoId ?? "") lodaViewModel.improveData(item.browseItem.videoId ?? "") //更改播放器播放类型 MP_PlayerManager.shared.setPlayType(.normal) MP_PlayerManager.shared.loadPlayer = lodaViewModel MP_AnalyticsManager.shared.player_b_listAction() } } case .Lists: //列表专辑 let listVC = MPPositive_ListShowViewController(item.browseItem.browseId ?? "", params: "", title: item.title ?? "", subtitle: item.subtitle ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "") self.parentController()?.navigationController?.pushViewController(listVC, animated: true) case .Artists: let artistVC = MPPositive_ArtistShowViewController(item.browseItem.artistId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "") self.parentController()?.navigationController?.pushViewController(artistVC, animated: true) } } func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { return MPPositive_PresentationController(presentedViewController: presented, presenting: presenting) } }