// MPPositive_PlayerCoverView.swift // MusicPlayer // Created by Mr.Zhou on 2024/5/8. import UIKit //B面播放器封面View(封面,标题,副标题,收藏,下载,进度条View) class MPPositive_PlayerCoverView: UIView { //下载进度条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 }() ///进度条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) // NotificationCenter.default.addObserver(self, selector: #selector(updateProgress(_:)), name: Notification.Name("DownloadProgressUpdated"), object: nil) // // // 恢复进度 // restoreDownloadProgress() } public func restoreDownloadProgress() { if let currentVideo = MP_PlayerManager.shared.loadPlayer.currentVideo, let videoURLString = currentVideo.song.resourceUrls?.first, let videoURL = URL(string: videoURLString) { if let progress = DownloadManager.shared.getProgress(for: videoURL) { //判断当前是正在下载的VideoID addCircularProgressBar(over: loadBtn) loadView.setProgress(to: progress) self.layoutIfNeeded() self.loadBtn.setBackgroundImage(UIImage(named: ""), for: .normal) self.loadBtn.setImage(UIImage(named: "download"), for: .normal) self.addCircularProgressBar(over: self.loadBtn) self.loadView.setProgress(to: progress) }else { //不是当前下载的videoID if (loadView.superview) != nil { loadView.removeFromSuperview() } self.loadBtn.setBackgroundImage(UIImage(named: "Song_Unload'logo"), for: .normal) self.loadBtn.setImage(UIImage(), for: .normal) self.loadBtn.setBackgroundImage(UIImage(named: "Song_Loaded'logo"), for: .selected) } } } @objc private func updateProgress(_ notification: Notification) { if let userInfo = notification.userInfo, let url = userInfo["url"] as? URL, let progress = userInfo["progress"] as? CGFloat, let currentVideo = MP_PlayerManager.shared.loadPlayer.currentVideo, let videoURLString = currentVideo.song.resourceUrls?.first, let videoURL = URL(string: videoURLString), videoURL == url { loadView.setProgress(to: progress) if loadView.progress.isEqual(to: 1.0){ self.loadView.removeFromSuperview() self.loadBtn.setBackgroundImage(UIImage(named: "Song_Loaded'logo"), for: .normal) self.loadBtn.setImage(UIImage(named: ""), for: .normal) } } } 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(loadBtn) loadBtn.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(loadBtn.snp.left).offset(-20*width) make.centerY.equalTo(loadBtn.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) } NotificationCenter.default.addObserver(self, selector: #selector(updateProgress(_:)), name: Notification.Name("DownloadProgressUpdated"), object: nil) // 恢复进度 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) } }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) } } } @objc private func loadActionClick(_ sender: UIButton) { if MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd == false { addCircularProgressBar(over: sender) self.loadBtn.setBackgroundImage(UIImage(named: ""), for: .normal) self.loadBtn.setImage(UIImage(named: "download"), for: .normal) if let currentVideo = MP_PlayerManager.shared.loadPlayer.currentVideo, let videoURLString = currentVideo.song.resourceUrls?.first, let videoURL = URL(string: videoURLString) { DownloadManager.shared.downloadVideo(from: videoURL, song: MP_PlayerManager.shared.loadPlayer.currentVideo.song, progressHandler: { [weak self] progress in DispatchQueue.main.async { self?.loadView.setProgress(to: progress) NotificationCenter.default.post(name: Notification.Name("DownloadProgressUpdated"), object: nil, userInfo: ["url": videoURL, "progress": progress]) } }, completion: { [weak self] result in 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 { self?.loadView.removeFromSuperview() MP_PlayerManager.shared.loadPlayer.currentVideo.reloadCollectionAndDownLoad() self?.loadBtn.setBackgroundImage(UIImage(named: "Song_Loaded'logo"), for: .normal) self?.loadBtn.setImage(UIImage(named: ""), for: .normal) print("完成了对\(song.title ?? "")的下载") MPPositive_LoadCoreModel.shared.reloadLoadSongViewModel(nil) } case .failure(let error): print("Download failed with error: \(error)") DispatchQueue.main.async { self?.loadView.removeFromSuperview() self?.loadBtn.setBackgroundImage(UIImage(named: "Song_Unload'logo"), for: .normal) self?.loadBtn.setImage(UIImage(named: ""), for: .normal) } MP_HUD.text("Download timed out, please download again", delay: 1.5, completion: nil) } }) } } } // //点击下载 // @objc private func loadActionClick(_ sender:UIButton) { // // if MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd == false{ // // // 添加圆形进度条到下载按钮位置 // addCircularProgressBar(over: sender) // // self.loadBtn.setBackgroundImage(UIImage(named: ""), for: .normal) // self.loadBtn.setImage(UIImage(named: "download"), for: .normal) // // //下载,检索当前播放音乐是否存在 // if MP_PlayerManager.shared.loadPlayer.currentVideo != nil { // // // 下载视频 // if let currentVideo = MP_PlayerManager.shared.loadPlayer.currentVideo, let videoURLString = currentVideo.song.resourceUrls?.first, let videoURL = URL(string: videoURLString) { // let videoId = currentVideo.song.videoId ?? "default_video_id" // DownloadManager.shared.downloadVideo(from: videoURL, videoId: videoId, progressView: loadView, completion: { [weak self] result in // switch result { // case .success(let fileURL): // let item = MPPositive_DownloadItemModel.create() // item.resourcePath = "\(fileURL)" // item.coverImage = URL(string: MP_PlayerManager.shared.loadPlayer.currentVideo.song.coverUrls!.first!) // item.reviewImage = URL(string: MP_PlayerManager.shared.loadPlayer.currentVideo.song.reviewUrls!.first!) // item.title = MP_PlayerManager.shared.loadPlayer.currentVideo.song.title // item.longBylineText = MP_PlayerManager.shared.loadPlayer.currentVideo.song.longBylineText // item.lengthText = MP_PlayerManager.shared.loadPlayer.currentVideo.song.lengthText // item.shortBylineText = MP_PlayerManager.shared.loadPlayer.currentVideo.song.shortBylineText // item.lyrics = MP_PlayerManager.shared.loadPlayer.currentVideo.lyrics // item.videoId = MP_PlayerManager.shared.loadPlayer.currentVideo.song.videoId // item.relatedID = MP_PlayerManager.shared.loadPlayer.currentVideo.song.relatedID // // MPPositive_DownloadItemModel.save() // DispatchQueue.main.async { // MP_PlayerManager.shared.loadPlayer.currentVideo.reloadCollectionAndDownLoad() // self?.loadBtn.setBackgroundImage(UIImage(named: "Song_Loaded'logo"), for: .normal) // self?.loadBtn.setImage(UIImage(named: ""), for: .normal) // } // // self?.loadView.removeFromSuperview() // case .failure(let error): // print("Download failed with error: \(error)") // self?.loadView.removeFromSuperview() // DispatchQueue.main.async { // self?.loadBtn.setBackgroundImage(UIImage(named: "Song_Unload'logo"), for: .normal) // self?.loadBtn.setImage(UIImage(named: ""), for: .normal) // } // MP_HUD.text("Download timed out, please download again", delay: 1.5, completion: nil) // } // }) // } // } // } // // } // // 添加圆形进度条 private func addCircularProgressBar(over button: UIButton) { loadView.removeFromSuperview() // 移除先前的进度视图(如果有) loadView = CircularProgressView(frame: button.bounds) addSubview(loadView) loadView.snp.makeConstraints { make in make.center.equalTo(button) make.width.height.equalTo(button) } } }