Music_Player3/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Player(播放器)/MPPositive_PlayerViewController.swift

588 lines
24 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// MPPositive_PlayerViewController.swift
// MusicPlayer
//
// Created by Mr.Zhou on 2024/4/29.
//
import UIKit
import Kingfisher
///b
class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewControllerTransitioningDelegate {
//
enum PlayerShowType:Int {
///
case showCover = 0
///
case showLyric = 1
}
//View
private var topShowType:PlayerShowType = .showCover{
didSet{
setSwitchAnimation(topShowType)
}
}
//MARK: - View
//
private lazy var leftPopBtn:UIButton = {
let btn = UIButton()
btn.backgroundColor = .init(hex: "#FFFFFF", alpha: 0.15)
//
btn.layer.borderColor = UIColor(hex: "#FFFFFF", alpha: 0.3).cgColor
btn.layer.borderWidth = 1*width
btn.layer.cornerRadius = 21*width
btn.layer.masksToBounds = true
//
btn.setImage(UIImage(named: "Player_Pop'logo"), for: .normal)
btn.addTarget(self, action: #selector(disMissClick(_ :)), for: .touchUpInside)
return btn
}()
//View(SONG|LYRICS)
private lazy var switchActionView:UIView = createSwitchActionView()
//SONG()
private lazy var songBtn:UIButton = createStatueBtn("SONG", color: .init(hex: "#FFFFFF", alpha: 0.85), tag: 0)
//LYRICS
private lazy var lyricsBtn:UIButton = createStatueBtn("LYRICS", color: .init(hex: "#FFFFFF", alpha: 0.45), tag: 1)
//
private lazy var relatedBtn:UIButton = {
let btn = UIButton()
btn.setBackgroundImage(UIImage(named: "Player_Related'logo"), for: .normal)
btn.addTarget(self, action: #selector(relatedContentClick(_ :)), for: .touchUpInside)
return btn
}()
//MARK: -
//
private lazy var backImageView:UIImageView = {
let imageView:UIImageView = .init()
imageView.image = placeholderImage
imageView.contentMode = .scaleAspectFill
return imageView
}()
//
private lazy var backBlurView:UIVisualEffectView = {
//
let blurEffect = UIBlurEffect(style: .dark)
//
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.alpha = 1
blurEffectView.isUserInteractionEnabled = false
return blurEffectView
}()
//MARK: -
//
private lazy var playBtn:UIButton = {
let btn:UIButton = .init()
btn.setBackgroundImage(UIImage(named: "Player_Pause'logo"), for: .normal)
btn.setBackgroundImage(UIImage(named: "Player_Player'logo"), for: .selected)
btn.addTarget(self, action: #selector(playClick(_ :)), for: .touchUpInside)
//
btn.isUserInteractionEnabled = false
return btn
}()
//
private lazy var listBtn:UIButton = {
let btn:UIButton = .init()
btn.setBackgroundImage(UIImage(named: "Player_List'logo"), for: .normal)
btn.addTarget(self, action: #selector(listClick(_ :)), for: .touchUpInside)
return btn
}()
//
private lazy var typeBtn:UIButton = {
let btn = UIButton()
btn.setBackgroundImage(UIImage(named: "List_NormolPlay'logo"), for: .normal)
btn.addTarget(self, action: #selector(typeClick(_ :)), for: .touchUpInside)
return btn
}()
//
private lazy var nextBtn:UIButton = {
let btn = UIButton()
btn.setBackgroundImage(UIImage(named: "Player_Next'logo"), for: .normal)
btn.addTarget(self, action: #selector(nextClick(_ :)), for: .touchUpInside)
return btn
}()
//
private lazy var perviousBtn:UIButton = {
let btn = UIButton()
btn.setBackgroundImage(UIImage(named: "Player_Pervious'logo"), for: .normal)
btn.addTarget(self, action: #selector(previousClick(_ :)), for: .touchUpInside)
return btn
}()
//
private lazy var activityIndicator:UIActivityIndicatorView = {
let activityIndicator:UIActivityIndicatorView = .init(frame: .init(x: 0, y: 0, width: 66*width, height: 66*width))
activityIndicator.style = .gray
activityIndicator.backgroundColor = .white
activityIndicator.layer.masksToBounds = true
activityIndicator.layer.cornerRadius = 33*width
activityIndicator.color = .black
return activityIndicator
}()
//View(View)
private lazy var coverView:MPPositive_PlayerCoverView = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: 480*width))
//View
private lazy var lyricsView:MPPositive_PlayerLyricView = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: 480*width))
var recommendBlock:(() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
//label
setTitle("")
configure()
//
NotificationCenter.notificationKey.add(observer: self, selector: #selector(playerReloadAction(_ :)), notificationName: .positive_player_reload)
NotificationCenter.notificationKey.add(observer: self, selector: #selector(statusSwitchAction(_:)), notificationName: .switch_player_status)
NotificationCenter.notificationKey.add(observer: self, selector: #selector(playerTypeSwitchAction(_:)), notificationName: .player_type_switch)
NotificationCenter.notificationKey.add(observer: self, selector: #selector(deleteListAction(_:)), notificationName: .player_delete_list)
//
MP_PlayerManager.shared.runActionBlock = { [weak self] (currentTime, duration) in
guard let self = self else { return }
DispatchQueue.main.async {
//
self.coverView.durationLabel.text = setTimesToMinSeconds(currentTime)
//
let remain:TimeInterval = duration - currentTime
self.coverView.maxTimesLabel.text = setTimesToMinSeconds(remain)
//
let value = currentTime/duration
self.coverView.sliderView.value = Float(value)
}
}
//
MP_PlayerManager.shared.cacheValueBlock = { [weak self] (value, duration) in
guard let self = self else { return }
DispatchQueue.main.async {
if value < duration {
//
let float = value/duration
self.coverView.progressView.setProgress(Float(float), animated: false)
}else {
//
self.coverView.progressView.setProgress(1, animated: false)
}
}
}
switch MP_PlayerManager.shared.getPlayState() {
case .Null://
playBtn.isSelected = false
playBtn.isUserInteractionEnabled = false
case .Playing://
playBtn.isSelected = true
playBtn.isUserInteractionEnabled = true
default://
playBtn.isSelected = false
playBtn.isUserInteractionEnabled = true
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//
if MP_PlayerManager.shared.loadPlayer?.currentVideo != nil {
uploadUI()
}
}
//
private func configure() {
//View
navView.addSubview(leftPopBtn)
leftPopBtn.snp.makeConstraints { make in
make.width.height.equalTo(42*width)
make.left.equalToSuperview().offset(16*width)
make.centerY.equalToSuperview()
}
navView.addSubview(relatedBtn)
relatedBtn.snp.makeConstraints { make in
make.width.height.equalTo(24*width)
make.right.equalToSuperview().offset(-16*width)
make.centerY.equalToSuperview()
}
navView.addSubview(switchActionView)
switchActionView.snp.makeConstraints { make in
make.height.equalToSuperview()
make.width.equalToSuperview().multipliedBy(0.45)
make.center.equalToSuperview()
}
//
view.addSubview(backImageView)
backImageView.snp.makeConstraints { make in
make.left.right.top.bottom.equalToSuperview()
}
view.addSubview(backBlurView)
backBlurView.snp.makeConstraints { make in
make.left.right.top.bottom.equalToSuperview()
}
let bottomImageView:UIImageView = .init(image: .init(named: "Player_Bottom'mask"))
bottomImageView.contentMode = .scaleAspectFill
bottomImageView.isUserInteractionEnabled = false
view.addSubview(bottomImageView)
bottomImageView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(286*width)
}
//
let bottomView = createBottomView()
view.addSubview(bottomView)
bottomView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(200*width)
}
//
view.addSubview(lyricsView)
lyricsView.snp.makeConstraints { make in
make.top.equalTo(navView.snp.bottom)
make.left.right.equalToSuperview()
make.height.equalTo(480*width)
}
lyricsView.isHidden = true
view.addSubview(coverView)
coverView.snp.makeConstraints { make in
make.top.equalTo(navView.snp.bottom)
make.left.right.equalToSuperview()
make.height.equalTo(480*width)
}
coverView.isHidden = false
}
//View
private func createSwitchActionView() -> UIView {
let actionView:UIView = UIView()
actionView.backgroundColor = .clear
actionView.addSubview(songBtn)
songBtn.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.centerX.equalToSuperview().multipliedBy(0.5)
}
actionView.addSubview(lyricsBtn)
lyricsBtn.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.centerX.equalToSuperview().multipliedBy(1.5)
}
//线View
let lineView:UIView = .init()
lineView.backgroundColor = .init(hex: "#FFFFFF", alpha: 0.45)
actionView.addSubview(lineView)
lineView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.width.equalTo(1*width)
make.height.equalTo(14*width)
}
//
return actionView
}
//
private func createStatueBtn(_ text:String = "text", color:UIColor, tag:Int) -> UIButton {
let btn = UIButton()
btn.setTitle(text, for: .normal)
btn.setTitleColor(color, for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 15, weight: .regular)
btn.tag = tag
btn.addTarget(self, action: #selector(switchActionClick(_ :)), for: .touchUpInside)
return btn
}
//View
private func createBottomView() -> UIView {
let bottomView:UIView = .init()
bottomView.backgroundColor = .clear
bottomView.addSubview(playBtn)
playBtn.snp.makeConstraints { make in
make.width.height.equalTo(66*width)
make.centerX.equalToSuperview()
make.centerY.equalToSuperview().multipliedBy(1.1)
}
bottomView.addSubview(activityIndicator)
activityIndicator.snp.makeConstraints { make in
make.center.equalTo(playBtn)
make.width.height.equalTo(playBtn)
}
let state = MP_PlayerManager.shared.getPlayState()
switch state {
case .Null:
activityIndicator.isHidden = false
activityIndicator.startAnimating()
default:
activityIndicator.isHidden = false
activityIndicator.stopAnimating()
}
bottomView.addSubview(listBtn)
listBtn.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-20*width)
make.centerY.equalTo(playBtn)
make.width.height.equalTo(24*width)
}
bottomView.addSubview(typeBtn)
typeBtn.snp.makeConstraints { make in
make.left.equalToSuperview().offset(20*width)
make.centerY.equalTo(playBtn)
make.width.height.equalTo(24*width)
}
bottomView.addSubview(nextBtn)
nextBtn.snp.makeConstraints { make in
make.width.height.equalTo(30*width)
make.centerY.equalTo(playBtn.snp.centerY)
make.right.equalToSuperview().offset(-98*width)
}
bottomView.addSubview(perviousBtn)
perviousBtn.snp.makeConstraints { make in
make.width.height.equalTo(30*width)
make.centerY.equalTo(playBtn.snp.centerY)
make.left.equalToSuperview().offset(98*width)
}
return bottomView
}
//MARK: -
private func uploadUI() {
DispatchQueue.main.async {
[weak self] in
guard let self = self, MP_PlayerManager.shared.loadPlayer?.currentVideo != nil else {return}
print("\(MP_PlayerManager.shared.loadPlayer?.currentVideo?.title ?? "")刷新了页面")
//
backImageView.kf.setImage(with: MP_PlayerManager.shared.loadPlayer.currentVideo?.coverUrl, placeholder: placeholderImage)
coverView.coverImageView.kf.setImage(with: MP_PlayerManager.shared.loadPlayer.currentVideo?.coverUrl, placeholder: placeholderImage)
coverView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
coverView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
lyricsView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
lyricsView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
lyricsView.lyricsLabel.text = (MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics ?? "").isEmpty == true ? "No Lyrics":MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics
coverView.downloadButton.state = (MPPositive_DownloadItemModel.fetch(.init(format: "videoId == %@", MP_PlayerManager.shared.loadPlayer.currentVideo?.song.videoId ?? "")).count != 0) ? .downloaded:.startDownload
coverView.downloadButton.isUserInteractionEnabled = !(MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false)
coverView.collectionSongBtn.isSelected = MP_PlayerManager.shared.loadPlayer.currentVideo?.isCollection ?? false
coverView.restoreDownloadProgress()
switchPlayTypeBtnIcon(typeBtn)
// activityIndicator.isHidden = true
// activityIndicator.stopAnimating()
}
}
//MARK: -
//
@objc private func playerReloadAction(_ sender:Notification) {
//
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
uploadUI()
//
coverView.sliderView.value = 0
//
coverView.durationLabel.text = setTimesToMinSeconds(0)
//
coverView.maxTimesLabel.text = setTimesToMinSeconds(0)
//
MP_PlayerManager.shared.play { [weak self] in
guard let self = self else { return }
//playBtn
playBtn.isUserInteractionEnabled = true
}
}
}
//
@objc private func statusSwitchAction(_ sender:Notification) {
if sender.object != nil {
let state:MP_PlayerStateType = sender.object as! MP_PlayerStateType
DispatchQueue.main.async {
[weak self] in
switch state {
case .Playing:
self?.playBtn.isSelected = true
self?.activityIndicator.isHidden = true
self?.activityIndicator.stopAnimating()
case .Pause:
self?.playBtn.isSelected = false
self?.activityIndicator.isHidden = true
self?.activityIndicator.stopAnimating()
default:
self?.playBtn.isSelected = false
self?.activityIndicator.isHidden = false
self?.activityIndicator.startAnimating()
}
}
}
}
//
@objc private func playerTypeSwitchAction(_ sender:Notification) {
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
switchPlayTypeBtnIcon(typeBtn)
}
}
//
@objc private func deleteListAction(_ sender:Notification) {
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
dismiss(animated: true)
}
}
//MARK: -
//dismiss
@objc private func disMissClick(_ sender:UIButton) {
dismiss(animated: true)
}
//|
@objc private func switchActionClick(_ sender:UIButton) {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
return
}
topShowType = .init(rawValue: sender.tag)!
}
//
private func setSwitchAnimation(_ sender: PlayerShowType) {
//segmentedView
switchActionView.isUserInteractionEnabled = false
switch sender {
case .showCover://
UIView.animate(withDuration: 0.4) {
[weak self] in
guard let self = self else {return}
//
coverView.alpha = 1.0
coverView.isHidden = false
//lyricView
lyricsView.alpha = 0.1
songBtn.setTitleColor(.init(hex: "#FFFFFF", alpha: 0.85), for: .normal)
lyricsBtn.setTitleColor(.init(hex: "#FFFFFF", alpha: 0.45), for: .normal)
} completion: { [weak self] (_) in
guard let self = self else {return}
//lyricListView
lyricsView.isHidden = true
//
switchActionView.isUserInteractionEnabled = true
}
case .showLyric://
UIView.animate(withDuration: 0.4) {
[weak self] in
guard let self = self else {return}
//
lyricsView.alpha = 1.0
lyricsView.isHidden = false
//coverView
coverView.alpha = 0.1
songBtn.setTitleColor(.init(hex: "#FFFFFF", alpha: 0.45), for: .normal)
lyricsBtn.setTitleColor(.init(hex: "#FFFFFF", alpha: 0.85), for: .normal)
} completion: { [weak self] (_) in
guard let self = self else {return}
//coverView
coverView.isHidden = true
//
switchActionView.isUserInteractionEnabled = true
}
}
}
//
@objc private func relatedContentClick(_ sender:UIButton) {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
return
}
//dismiss
if recommendBlock != nil {
recommendBlock!()
}
dismiss(animated: true)
}
////
@objc private func playClick(_ sender:UIButton) {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
return
}
guard MP_PlayerManager.shared.loadPlayer != nil else {
return
}
//
switch MP_PlayerManager.shared.getPlayState() {
case .Null:
//
MP_PlayerManager.shared.play { [weak self] in
guard let self = self else { return }
//
coverView.sliderView.value = 0
}
case .Playing:
//
MP_PlayerManager.shared.pause {
[weak self] in
}
case .Pause:
//
MP_PlayerManager.shared.resume {
[weak self] in
}
}
}
//
@objc private func listClick(_ sender:UIButton) {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
return
}
if MP_PlayerManager.shared.loadPlayer != nil {
MPPositive_ModalType = .PlayerList
let listVC = MPPositive_PlayerListShowViewController()
listVC.transitioningDelegate = self
listVC.modalPresentationStyle = .custom
present(listVC, animated: true)
}
}
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return MPPositive_PresentationController(presentedViewController: presented, presenting: presenting)
}
////
@objc private func typeClick(_ sender:UIButton) {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
return
}
MPPositive_Debouncer.shared.call {
[weak self] in
guard let self = self else {return}
//
var value = MP_PlayerManager.shared.getPlayType().rawValue
value += 1
if value > 2 {
value = 0
}
MP_PlayerManager.shared.setPlayType(.init(rawValue: value)!)
}
}
//
@objc private func nextClick(_ sender:UIButton) {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
return
}
guard MP_PlayerManager.shared.loadPlayer?.currentVideo != nil else {
return
}
MPPositive_Debouncer.shared.call {
[weak self] in
guard let self = self else {return}
coverView.sliderView.value = 0
MP_PlayerManager.shared.nextEvent()
}
}
//
@objc private func previousClick(_ sender:UIButton) {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
return
}
guard MP_PlayerManager.shared.loadPlayer?.currentVideo != nil else {
return
}
MPPositive_Debouncer.shared.call {
[weak self] in
guard let self = self else {return}
coverView.sliderView.value = 0
MP_PlayerManager.shared.previousEvent()
}
}
}