406 lines
15 KiB
Swift
406 lines
15 KiB
Swift
//
|
||
// PlayerViewController.swift
|
||
// MusicPlayer
|
||
//
|
||
// Created by Mr.Zhou on 2024/3/28.
|
||
//
|
||
|
||
import UIKit
|
||
///播放器显示状态
|
||
enum MPSideA_PlayerState {
|
||
case Dark
|
||
case Light
|
||
///对应的按钮背景色
|
||
var buttonBGColor:UIColor{
|
||
switch self {
|
||
case .Dark:
|
||
return .init(hex: "#FFFFFF", alpha: 0.15)
|
||
case .Light:
|
||
return .init(hex: "#F2F2F2")
|
||
}
|
||
}
|
||
///页面背景色
|
||
var viewBGColor:UIColor{
|
||
switch self {
|
||
case .Dark:
|
||
return .init(hex: "#000000")
|
||
case .Light:
|
||
return .init(hex: "#FFFFFF")
|
||
}
|
||
}
|
||
///文本字体颜色
|
||
var textColor:UIColor{
|
||
switch self {
|
||
case .Dark:
|
||
return .init(hex: "#FFFFFF")
|
||
case .Light:
|
||
return .init(hex: "#000000")
|
||
}
|
||
}
|
||
///滑块图片
|
||
var thumbImage:UIImage{
|
||
switch self {
|
||
case .Dark:
|
||
return UIImage(named: "Thumb dark'logo")!
|
||
case .Light:
|
||
return UIImage(named: "Thumb light'logo")!
|
||
}
|
||
}
|
||
///滑轨颜色集合
|
||
var minTrackColors:[UIColor]{
|
||
switch self {
|
||
case .Dark:
|
||
return [UIColor(hex: "#FFFFFF", alpha: 0.3), UIColor(hex: "#FFFFFF", alpha: 0.3)]
|
||
case .Light:
|
||
return [UIColor(hex: "#80F988", alpha: 0.2), UIColor(hex: "#80F988", alpha: 0.2)]
|
||
}
|
||
}
|
||
///毛玻璃效果
|
||
var effctView:UIBlurEffect{
|
||
switch self {
|
||
case .Dark:
|
||
if #available(iOS 13.0, *) {
|
||
return UIBlurEffect(style: .systemThickMaterialDark)
|
||
} else {
|
||
return UIBlurEffect(style: .dark)
|
||
}
|
||
case .Light:
|
||
return UIBlurEffect(style: .light)
|
||
}
|
||
}
|
||
}
|
||
///播放器页面
|
||
@objcMembers class MPSideA_PlayerViewController: MPSideA_BaseViewController {
|
||
@IBOutlet weak var disMissBtn: UIButton!
|
||
@IBOutlet weak var titleLabel: UILabel!
|
||
@IBOutlet weak var effectView: UIVisualEffectView!
|
||
@IBOutlet weak var backImageView: UIImageView!
|
||
@IBOutlet weak var coverImageView: UIImageView!
|
||
@IBOutlet weak var nameLabel: UILabel!
|
||
@IBOutlet weak var slider: MP_PlayerSlider!{
|
||
didSet{
|
||
slider.thumbImage = state.thumbImage
|
||
slider.trackHeight = 10*width
|
||
slider.minTrackColors = state.minTrackColors
|
||
slider.minTrackLocations = [0.0,1.0]
|
||
slider.maxTrackColors = state.minTrackColors
|
||
slider.maxTrackLocations = [0.0,1.0]
|
||
slider.setNeedsDisplay()
|
||
}
|
||
}
|
||
@IBOutlet weak var volumeLabel: UILabel!
|
||
@IBOutlet weak var lampView: MPSideA_PlayerActionView!{
|
||
didSet{
|
||
lampView.darkImage = UIImage(named: "Lamp dark'logo")
|
||
lampView.lightImage = UIImage(named: "Lamp light'logo")
|
||
lampView.isDark = true
|
||
lampView.isPlaying = false
|
||
lampView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(lampActionClick(_ :))))
|
||
}
|
||
}
|
||
@IBOutlet weak var timerView: MPSideA_PlayerActionView!{
|
||
didSet{
|
||
timerView.darkImage = UIImage(named: "Timer dark'logo")
|
||
timerView.lightImage = UIImage(named: "Timer light'logo")
|
||
timerView.playingImage = UIImage(named: "Timer playing'logo")
|
||
timerView.isDark = true
|
||
timerView.isPlaying = false
|
||
timerView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(timerActionClick(_ :))))
|
||
}
|
||
}
|
||
@IBOutlet weak var timerLabel: UILabel!
|
||
@IBOutlet weak var autoView: MPSideA_PlayerActionView!{
|
||
didSet{
|
||
autoView.darkImage = UIImage(named: "Auto dark'logo")
|
||
autoView.lightImage = UIImage(named: "Auto light'logo")
|
||
autoView.playingImage = UIImage(named: "Auto playing'logo")
|
||
autoView.isDark = true
|
||
autoView.isPlaying = false
|
||
autoView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(autoActionClick(_ :))))
|
||
}
|
||
}
|
||
@IBOutlet weak var playBtn: UIButton!
|
||
@IBOutlet weak var maskView: UIImageView!
|
||
//图片旋转计时器
|
||
private var timer:CADisplayLink!
|
||
//播放器页面显示状态,默认为黑夜(切换后对于页面内容作出改变)
|
||
private lazy var state:MPSideA_PlayerState = .Dark{
|
||
didSet{
|
||
setUpState(state)
|
||
}
|
||
}
|
||
//当前系统音量
|
||
private lazy var volume:Float = 0{
|
||
didSet{
|
||
//更新label值
|
||
volumeLabel.text = String(format: "Volume:%.2f", volume*100)
|
||
//调整slider
|
||
let value = volume
|
||
slider.value = value
|
||
}
|
||
}
|
||
//指定自动播放需要的分贝值
|
||
private lazy var decibels:Float = 0.5
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
view.backgroundColor = state.viewBGColor
|
||
playBtn.isSelected = MPSideA_MediaCenterManager.shared.getPlayerState() == .Playing
|
||
//启动音量绑定
|
||
MPSideA_VolumeManager.shared.createVolume()
|
||
//设置音量
|
||
volume = MPSideA_VolumeManager.shared.getVolume()
|
||
if let music = MPSideA_MediaCenterManager.shared.getMusic() {
|
||
//设置音乐展示
|
||
nameLabel.text = music.title
|
||
coverImageView.image = UIImage(data: music.cover)
|
||
backImageView.image = UIImage(data: music.cover)
|
||
}
|
||
lampView.backgroundColor = state.buttonBGColor
|
||
timerView.backgroundColor = state.buttonBGColor
|
||
autoView.backgroundColor = state.buttonBGColor
|
||
|
||
//触发音乐缺失闭包
|
||
nullMusicAction = {
|
||
[weak self] in
|
||
//退出该页面
|
||
self?.navigationController?.popViewController(animated: true)
|
||
}
|
||
//初始化计时器
|
||
timer = CADisplayLink(target: self, selector: #selector(coverRotationalAction(_ :)))
|
||
//一秒执行多少次
|
||
timer.preferredFramesPerSecond = 20
|
||
//开辟线程
|
||
timer.add(to: RunLoop.current, forMode: .common)
|
||
timer.isPaused = true
|
||
addNotification()
|
||
}
|
||
override func viewWillAppear(_ animated: Bool) {
|
||
super.viewWillAppear(animated)
|
||
//根据播放器状态设置计时器状态
|
||
timer.isPaused = !(MPSideA_MediaCenterManager.shared.getPlayerState() == .Playing)
|
||
}
|
||
override func viewWillDisappear(_ animated: Bool) {
|
||
super.viewWillDisappear(animated)
|
||
//停止监听器
|
||
MPSideA_MediaCenterManager.shared.stopMonitor()
|
||
}
|
||
deinit {
|
||
//移除所有通知
|
||
NotificationCenter.default.removeObserver(self)
|
||
//销毁音量绑定
|
||
MPSideA_VolumeManager.shared.destroyVolume()
|
||
//销毁帧计时器
|
||
timer = nil
|
||
}
|
||
//添加通知与监听
|
||
private func addNotification() {
|
||
//添加通知
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(timesAction(_ :)), notificationName: .sideA_time_times)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(volumeChangeAction(_ :)), notificationName: .sideA_volume_change)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(playMusicAction(_ :)), notificationName: .sideA_play_music)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(pauseMusicAction(_ :)), notificationName: .sideA_pause_music)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(resumeMusicAction(_ :)), notificationName: .sideA_resume_music)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(stopMusicAction(_ :)), notificationName: .sideA_stop_music)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(fileMissAction(_ :)), notificationName: .sideA_null_music)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(openMonitorAction(_ :)), notificationName: .sideA_open_monitor)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(stopMonitorAction(_ :)), notificationName: .sideA_stop_monitor)
|
||
}
|
||
}
|
||
//MARK: - 交互事件
|
||
extension MPSideA_PlayerViewController {
|
||
//退出事件
|
||
@IBAction func disMissAction(_ sender: UIButton) {
|
||
dismiss(animated: true)
|
||
}
|
||
//手动调整音量
|
||
@IBAction func sliderVolumeAction(_ sender: MP_PlayerSlider) {
|
||
let value = sender.value
|
||
MPSideA_VolumeManager.shared.setVolume(value)
|
||
}
|
||
//切换页面显示状态
|
||
@objc private func lampActionClick(_ sender: MPSideA_PlayerActionView) {
|
||
if state == .Dark {
|
||
state = .Light
|
||
}else {
|
||
state = .Dark
|
||
}
|
||
}
|
||
//设置倒计时
|
||
@objc private func timerActionClick(_ sender: MPSideA_PlayerActionView) {
|
||
//关闭麦克风监听器
|
||
MPSideA_MediaCenterManager.shared.stopMonitor()
|
||
MPSideA_ModalType = .Timer
|
||
let timerVC = MPSideA_CountTimerViewController()
|
||
timerVC.transitioningDelegate = self
|
||
timerVC.modalPresentationStyle = .custom
|
||
present(timerVC, animated: true)
|
||
}
|
||
//自动播放(当环境分贝超过指定值时播放)
|
||
@objc private func autoActionClick(_ sender: MPSideA_PlayerActionView) {
|
||
guard authorize(observe: self) == true else {
|
||
print("No Microphone Access")
|
||
return
|
||
}
|
||
if autoView.isPlaying {
|
||
//关闭麦克风监听器
|
||
MPSideA_MediaCenterManager.shared.stopMonitor()
|
||
}else {
|
||
//启动监听器
|
||
MPSideA_MediaCenterManager.shared.openMonitor(0.5)
|
||
}
|
||
}
|
||
//播放/暂停
|
||
@IBAction func playClick(_ sender: UIButton) {
|
||
//关闭麦克风监听器
|
||
MPSideA_MediaCenterManager.shared.stopMonitor()
|
||
//弹出切割广告
|
||
MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable(completion: nil)
|
||
guard let music = MPSideA_MediaCenterManager.shared.getMusic() else {
|
||
//播放器未能持有音乐实体
|
||
print("No Data Music")
|
||
return
|
||
}
|
||
switch MPSideA_MediaCenterManager.shared.getPlayerState() {
|
||
case .Null://启动播放
|
||
MPSideA_MediaCenterManager.shared.playerStart(music, actionType: .Normal)
|
||
case .Playing://暂停播放
|
||
MPSideA_MediaCenterManager.shared.playerPause()
|
||
case .Pause://继续播放
|
||
MPSideA_MediaCenterManager.shared.playerResume()
|
||
}
|
||
}
|
||
}
|
||
//MARK: - 业务处理
|
||
extension MPSideA_PlayerViewController: UIViewControllerTransitioningDelegate {
|
||
//声音值切换
|
||
@objc fileprivate func volumeChangeAction(_ sender:Notification) {
|
||
guard let value = sender.object as? Float else {
|
||
return
|
||
}
|
||
volume = value
|
||
}
|
||
//页面状态切换
|
||
private func setUpState(_ state:MPSideA_PlayerState) {
|
||
view.backgroundColor = state.viewBGColor
|
||
//黑夜展示背景图,白天隐藏
|
||
backImageView.isHidden = !(state == .Dark)
|
||
maskView.isHidden = !(state == .Dark)
|
||
titleLabel.textColor = state.textColor
|
||
//调整毛玻璃
|
||
effectView.effect = state.effctView
|
||
nameLabel.textColor = state.textColor
|
||
slider.thumbImage = state.thumbImage
|
||
slider.minTrackColors = state.minTrackColors
|
||
slider.maxTrackColors = state.minTrackColors
|
||
slider.setNeedsDisplay()
|
||
volumeLabel.textColor = state.textColor
|
||
//更改按钮的背景色
|
||
disMissBtn.backgroundColor = state.buttonBGColor
|
||
lampView.backgroundColor = state.buttonBGColor
|
||
timerView.backgroundColor = state.buttonBGColor
|
||
autoView.backgroundColor = state.buttonBGColor
|
||
//更改按钮的高亮
|
||
disMissBtn.isSelected = !(state == .Dark)
|
||
lampView.isDark = (state == .Dark)
|
||
timerView.isDark = (state == .Dark)
|
||
autoView.isDark = (state == .Dark)
|
||
}
|
||
|
||
//计时值变化事件
|
||
@objc private func timesAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
let time = sender.object as! TimeInterval
|
||
timerView.isPlaying = true
|
||
timerLabel.isHidden = false
|
||
timerLabel.text = setTimesToMins(time)
|
||
}
|
||
}
|
||
//计时结束事件
|
||
@objc private func completeAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
timerView.isPlaying = false
|
||
timerLabel.isHidden = true
|
||
timerLabel.text = "00"
|
||
}
|
||
}
|
||
//启动音乐播放器
|
||
@objc private func playMusicAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
playBtn.isSelected = true
|
||
autoView.isPlaying = false
|
||
//旋转图片
|
||
coverImageView.transform = .identity
|
||
timer.isPaused = false
|
||
}
|
||
}
|
||
//暂停音乐播放器
|
||
@objc private func pauseMusicAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
playBtn.isSelected = false
|
||
timer.isPaused = true
|
||
}
|
||
}
|
||
//继续音乐播放器
|
||
@objc private func resumeMusicAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
playBtn.isSelected = true
|
||
timer.isPaused = false
|
||
}
|
||
}
|
||
//终止音乐播放器
|
||
@objc private func stopMusicAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
playBtn.isSelected = false
|
||
timerView.isPlaying = false
|
||
timerLabel.isHidden = true
|
||
timerLabel.text = "00"
|
||
timer.isPaused = true
|
||
coverImageView.transform = .identity
|
||
}
|
||
}
|
||
//开启麦克风监听器
|
||
@objc private func openMonitorAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
autoView.isPlaying = true
|
||
}
|
||
}
|
||
//关闭麦克风监听器
|
||
@objc private func stopMonitorAction(_ sender:Notification) {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
autoView.isPlaying = false
|
||
}
|
||
}
|
||
|
||
//计时器事件-封面图片随着音乐播放器状态旋转自身
|
||
@objc private func coverRotationalAction(_ link:CADisplayLink) {
|
||
//当音乐播放器启动后,使得封面图片无限旋转,当音乐播放器暂停/结束后,图片会回正
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else { return }
|
||
let angle = CGFloat.pi / 200
|
||
coverImageView.transform = coverImageView.transform.rotated(by: angle)
|
||
}
|
||
|
||
}
|
||
|
||
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
|
||
return MPSideA_PresentationController(presentedViewController: presented, presenting: presenting)
|
||
}
|
||
}
|