// MPPositive_PlayerCoverView.swift // MusicPlayer // Created by Mr.Zhou on 2024/5/8. import UIKit import DownloadButton //B面播放器封面View(封面,标题,副标题,收藏,下载,进度条View) class MPPositive_PlayerCoverView: UIView, PKDownloadButtonDelegate { //下载进度条View // private var loadView = CircularProgressView() ///封面 lazy var coverImageView:UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFill imageView.layer.masksToBounds = true imageView.layer.cornerRadius = 16*width return imageView }() ///标题 lazy var titleLabel:UILabel = createLabel(font: .systemFont(ofSize: 22*width, weight: .regular), textColor: .init(hex: "#FFFFFF", alpha: 0.85), textAlignment: .left) ///副标题 lazy var subtitleLabel:UILabel = createLabel(font: .systemFont(ofSize: 12*width, weight: .regular), textColor: .init(hex: "#EEEEEE", alpha: 0.6), textAlignment: .left) ///收藏按钮 lazy var collectionSongBtn:UIButton = { let btn = UIButton() btn.setBackgroundImage(UIImage(named: "List_UnCollection'logo"), for: .normal) btn.setBackgroundImage(UIImage(named: "List_Collectioned'logo"), for: .selected) btn.addTarget(self, action: #selector(collectionSwitchClick(_ :)), for: .touchUpInside) return btn }() ///下载按钮 // lazy var loadBtn:UIButton = { // let btn:UIButton = .init() // btn.setBackgroundImage(UIImage(named: "Song_Unload'logo"), for: .normal) // btn.setBackgroundImage(UIImage(named: "Song_Loaded'logo"), for: .selected) // btn.addTarget(self, action: #selector(loadActionClick(_ :)), for: .touchUpInside) // return btn // }() ///下载按钮 lazy var downloadButton:PKDownloadButton = { let btn:PKDownloadButton = .init() //开始下载状态 btn.startDownloadButton.cleanDefaultAppearance() btn.startDownloadButton.setBackgroundImage(UIImage(named: "Song_Unload'logo"), for: .normal) //下载结束状态 btn.downloadedButton.setBackgroundImage(UIImage(named: "Song_Loaded'logo"), for: .normal) btn.downloadedButton.isUserInteractionEnabled = false //停止下载状态 btn.stopDownloadButton.stopButton.setImage(UIImage(named: "download"), for: .normal) btn.stopDownloadButton.isUserInteractionEnabled = false btn.stopDownloadButton.tintColor = UIColor(hex: "#80F988") btn.stopDownloadButton.stopButtonWidth = 1 btn.stopDownloadButton.stopButton.backgroundColor = .clear btn.stopDownloadButton.stopButton.tintColor = .clear btn.stopDownloadButton.filledLineWidth = 3*width btn.stopDownloadButton.filledLineStyleOuter = true //加载状态设置 btn.pendingView.tintColor = UIColor(hex: "#80F988") btn.pendingView.radius = 12*width btn.pendingView.emptyLineRadians = 2*width btn.pendingView.spinTime = 3 btn.delegate = self return btn }() ///进度条View lazy var sliderView:MPPositive_PlayerSilder = { let sliderView:MPPositive_PlayerSilder = .init(frame: .init(x: 0, y: 0, width: 335*width, height: 6*width)) sliderView.addTarget(self, action: #selector(seekProgressClick(_:forEvent:)), for: .valueChanged) sliderView.addTarget(self, action: #selector(seekProgressClick(_:forEvent:)), for: .touchDown) sliderView.addTarget(self, action: #selector(seekProgressClick(_:forEvent:)), for: .touchUpInside) return sliderView }() ///缓存条View lazy var progressView:UIProgressView = { let progressView:UIProgressView = .init() progressView.isUserInteractionEnabled = true progressView.progressTintColor = .init(hex: "#FFFFFF", alpha: 0.3) progressView.trackTintColor = .clear progressView.progress = 0 return progressView }() ///当前播放时间值Label lazy var durationLabel:UILabel = createLabel("00:00" ,font: .systemFont(ofSize: 12*width, weight: .medium), textColor: .init(hex: "#FFFFFF", alpha: 0.85), textAlignment: .left) ///最大播放时间值Label lazy var maxTimesLabel:UILabel = createLabel("00:00" ,font: .systemFont(ofSize: 12*width, weight: .medium), textColor: .init(hex: "#FFFFFF", alpha: 0.6), textAlignment: .right) ///断网提醒View private lazy var maskNotReachableView:UIView = { let maskView = UIView() maskView.backgroundColor = .init(hex: "#000000", alpha: 0.7) maskView.layer.masksToBounds = true maskView.layer.cornerRadius = 16*width //放置一个label let noticeLabel:UILabel = createLabel("The network connection is disconnected and the player will stop loading music. Please restore the network as soon as possible!", font: .systemFont(ofSize: 18, weight: .medium), textColor: .white, textAlignment: .center, lines: 0) maskView.addSubview(noticeLabel) noticeLabel.snp.makeConstraints { make in make.center.equalToSuperview() make.width.equalToSuperview().multipliedBy(0.7) } return maskView }() override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .clear configure() //添加监听 NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkNotReachableAction(_:)), notificationName: .net_switch_notReachable) NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkReachableAction(_:)), notificationName: .net_switch_reachable) } required init?(coder: NSCoder) { super.init(coder: coder) } //对于下载按钮状态的刷新变动 public func restoreDownloadProgress() { guard let currentVideo = MP_PlayerManager.shared.loadPlayer?.currentVideo else { return } //判断当前播放video是否正在下载 if let progress = MP_DownloadManager.shared.getProgress(for: currentVideo.song.videoId) { DispatchQueue.main.async { [weak self] in guard let self = self else {return} //是正在下载的URL downloadButton.state = .downloading downloadButton.isUserInteractionEnabled = false //调整下载的进度 downloadButton.stopDownloadButton.progress = progress } }else { //不是正在下载的内容,判断是否下载了 downloadButton.state = (MPPositive_DownloadItemModel.fetch(.init(format: "videoId == %@", currentVideo.song.videoId ?? "")).count != 0) ? .downloaded:.startDownload downloadButton.isUserInteractionEnabled = true } } deinit { NotificationCenter.default.removeObserver(self) } //视图配置 private func configure() { //配置封面图 addSubview(coverImageView) coverImageView.snp.makeConstraints { make in make.width.equalTo(335*width) make.height.equalTo(330*width) make.centerX.equalToSuperview() make.top.equalToSuperview().offset(12*width) } addSubview(maskNotReachableView) maskNotReachableView.snp.makeConstraints { make in make.left.right.top.bottom.equalTo(coverImageView) } maskNotReachableView.isHidden = true //添加标题 addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.left.equalTo(coverImageView.snp.left) make.top.equalTo(coverImageView.snp.bottom).offset(36*width) make.right.equalTo(coverImageView.snp.right).offset(-100*width) } addSubview(subtitleLabel) subtitleLabel.snp.makeConstraints { make in make.left.right.equalTo(titleLabel) make.top.equalTo(titleLabel.snp.bottom).offset(6*width) } //配置下载和收藏按钮 addSubview(downloadButton) downloadButton.snp.makeConstraints { make in make.right.equalTo(coverImageView.snp.right).offset(-12*width) make.top.equalTo(coverImageView.snp.bottom).offset(47*width) make.width.height.equalTo(24*width) } addSubview(collectionSongBtn) collectionSongBtn.snp.makeConstraints { make in make.right.equalTo(downloadButton.snp.left).offset(-20*width) make.centerY.equalTo(downloadButton.snp.centerY) make.width.height.equalTo(24*width) } addSubview(progressView) progressView.snp.makeConstraints { make in make.top.equalTo(subtitleLabel.snp.bottom).offset(25*width) make.centerX.equalToSuperview() make.width.equalTo(335*width) make.height.equalTo(6*width) } //配置进度条和时间label addSubview(sliderView) sliderView.snp.makeConstraints { make in make.left.right.top.bottom.equalTo(progressView) } addSubview(durationLabel) durationLabel.snp.makeConstraints { make in make.left.equalTo(sliderView.snp.left) make.top.equalTo(sliderView.snp.bottom).offset(5*width) } addSubview(maxTimesLabel) maxTimesLabel.snp.makeConstraints { make in make.right.equalTo(sliderView.snp.right) make.top.equalTo(sliderView.snp.bottom).offset(5*width) } // 恢复进度 restoreDownloadProgress() } //网络不可用时触发 @objc private func netWorkNotReachableAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else {return} maskNotReachableView.isHidden = false } } //网络可用时触发 @objc private func netWorkReachableAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else {return} maskNotReachableView.isHidden = true } } //调整音乐进度 @objc private func seekProgressClick(_ sender: UISlider, forEvent event: UIEvent) { //获取touchEvent let touchEvent = event.allTouches?.first //判断点击事件状态 switch touchEvent?.phase { case .began://开始拖动 //让播放器进入调整状态 MP_PlayerManager.shared.setEditPorgressStatu() case .moved://移动中 break case .ended://结束 let value = sender.value //让播放器恢复状态 MP_PlayerManager.shared.setEditProgressEnd(value) default: break } } //切换当前列表收藏状态 @objc private func collectionSwitchClick(_ sender:UIButton) { if self.collectionSongBtn.isSelected == true{ self.collectionSongBtn.isSelected = false if MP_PlayerManager.shared.loadPlayer.currentVideo != nil{ MPPositive_CollectionSongModel.fetch(.init(format: "videoId == %@", MP_PlayerManager.shared.loadPlayer.currentVideo.song.videoId)).forEach { i in if i.videoId == MP_PlayerManager.shared.loadPlayer.currentVideo.song.videoId{ MPPositive_CollectionSongModel.delete(i) } } MP_PlayerManager.shared.loadPlayer.currentVideo.reloadCollectionAndDownLoad() MPPositive_LoadCoreModel.shared.reloadCollectionSongViewModel(nil) MP_AnalyticsManager.shared.player_b_unlove_clickAction(MP_PlayerManager.shared.loadPlayer.currentVideo?.song.videoId ?? "", videoname: MP_PlayerManager.shared.loadPlayer.currentVideo?.song.title ?? "", artistname: MP_PlayerManager.shared.loadPlayer.currentVideo?.song.shortBylineText ?? "") } }else{ self.collectionSongBtn.isSelected = true if MP_PlayerManager.shared.loadPlayer.currentVideo != nil{ let item = MPPositive_CollectionSongModel.create() item.title = MP_PlayerManager.shared.loadPlayer.currentVideo.title item.videoId = MP_PlayerManager.shared.loadPlayer.currentVideo.song.videoId item.subtitle = MP_PlayerManager.shared.loadPlayer.currentVideo.subtitle item.coverImage = MP_PlayerManager.shared.loadPlayer.currentVideo.coverUrl item.lyricsID = MP_PlayerManager.shared.loadPlayer.currentVideo.song.lyricsID item.relatedID = MP_PlayerManager.shared.loadPlayer.currentVideo.song.relatedID MPPositive_CollectionSongModel.save() MP_PlayerManager.shared.loadPlayer.currentVideo.reloadCollectionAndDownLoad() MPPositive_LoadCoreModel.shared.reloadCollectionSongViewModel(nil) MP_AnalyticsManager.shared.player_b_love_clickAction(MP_PlayerManager.shared.loadPlayer.currentVideo?.song.videoId ?? "", videoname: MP_PlayerManager.shared.loadPlayer.currentVideo?.song.title ?? "", artistname: MP_PlayerManager.shared.loadPlayer.currentVideo?.song.shortBylineText ?? "") } } } //下载按钮代理 func downloadButtonTapped(_ downloadButton: PKDownloadButton!, currentState state: PKDownloadButtonState) { guard MP_PlayerManager.shared.loadPlayer?.currentVideo != nil, MP_PlayerManager.shared.loadPlayer?.currentVideo?.isDlownd == false else { return } //当前音乐没有下载 switch state { case .startDownload: //开始状态,点击时准备加载 //切换为准备状态 downloadButton.state = .pending //禁止用户操作 downloadButton.isUserInteractionEnabled = false //当开始下载时 guard let currentVideo = MP_PlayerManager.shared.loadPlayer?.currentVideo, let videoURL = currentVideo.resourcePlayerURL else { MP_HUD.text("An error occurred while downloading. Please download again.", delay: 1.0) { downloadButton.state = .startDownload downloadButton.isUserInteractionEnabled = true } return } MP_AnalyticsManager.shared.player_b_download_clickAction(currentVideo.song.videoId, videoname: currentVideo.song.title ?? "", artistname: currentVideo.song.shortBylineText ?? "") //执行下载 MP_DownloadManager.shared.downloadVideo(from: videoURL, song: currentVideo.song) { [weak self] progress in guard let self = self, currentVideo.song.videoId == MP_PlayerManager.shared.loadPlayer.currentVideo.song.videoId else { //不是同一个 downloadButton.state = (MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false) ? .downloaded:.startDownload downloadButton.isUserInteractionEnabled = !(MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false) return } downloadButton.state = .downloading downloadButton.stopDownloadButton.progress = progress } completion: { [weak self] result in guard let self = self else {return} //下载结束,判断成功或失败 switch result { case .success(let song): //添加数据 let item = MPPositive_DownloadItemModel.create() item.coverImage = song.coverUrls!.last item.reviewImage = song.reviewUrls!.last item.title = song.title item.longBylineText = song.longBylineText item.lengthText = song.lengthText item.shortBylineText = song.shortBylineText item.lyrics = song.lyrics item.lyricsID = song.lyricsID item.videoId = song.videoId item.relatedID = song.relatedID MPPositive_DownloadItemModel.save() DispatchQueue.main.async { //回归主线程,判断下载的是否为当前歌曲 if song.videoId == MP_PlayerManager.shared.loadPlayer?.currentVideo?.song.videoId { //是当前这首,刷新一下当前播放音乐的下载状态 MP_PlayerManager.shared.loadPlayer.currentVideo.reloadCollectionAndDownLoad() }else { //不是这首,那就不管他 } print("完成了对\(song.title ?? "")的下载") //按钮变为下载结束状态 downloadButton.state = .downloaded downloadButton.isUserInteractionEnabled = false //更新数据库管理类 MPPositive_LoadCoreModel.shared.reloadLoadSongViewModel(nil) MP_AnalyticsManager.shared.player_b_downloadsuccess_actionAction(item.videoId, videoname: item.title ?? "", artistname: item.shortBylineText ?? "") } case .failure(let error): //失败了,打印错误 print("下载报错,错误详情\(error)") DispatchQueue.main.async { //按钮回归可用状态 downloadButton.state = .startDownload downloadButton.isUserInteractionEnabled = true } MP_HUD.text("An error occurred while downloading. Please download again.", delay: 1.5, completion: nil) } } case .pending://准备状态 break case .downloading: break case .downloaded: break @unknown default: break } } }