244 lines
9.4 KiB
Swift
244 lines
9.4 KiB
Swift
//
|
||
// Macro.swift
|
||
// MusicPlayer
|
||
//
|
||
// Created by Mr.Zhou on 2024/3/25.
|
||
//
|
||
import UIKit
|
||
import Foundation
|
||
import AVFoundation
|
||
import AppTrackingTransparency
|
||
import AdSupport
|
||
@_exported import JXSegmentedView
|
||
@_exported import JXPagingView
|
||
//给JXPagingListContainerView添加extension,表示遵从JXSegmentedViewListContainer的协议
|
||
extension JXPagingListContainerView: JXSegmentedViewListContainer {}
|
||
//MARK: - 常用宏定义
|
||
///屏幕宽
|
||
let screen_Width = UIScreen.main.bounds.width
|
||
///屏幕高
|
||
let screen_Height = UIScreen.main.bounds.height
|
||
///像素宽比值
|
||
let width = screen_Width / 375
|
||
///像素高比值
|
||
let height = screen_Height / 667
|
||
///状态栏高度
|
||
#if __IPHONE_13_0
|
||
let statusBarHeight:CGFloat = UIApplication.shared.windows.first?.windowScene?.statusBarManager?.statusBarFrame.size.height
|
||
#else
|
||
let statusBarHeight:CGFloat = UIApplication.shared.statusBarFrame.size.height
|
||
#endif
|
||
///状态栏和导航栏的总高度
|
||
let navAndstatusBarHeight = statusBarHeight + 44
|
||
///判断是否是刘海屏
|
||
let iphoneX = ((statusBarHeight != 20) ? true : false)
|
||
///获取版本号
|
||
let LOCAL_RELEASE_VERSION = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
|
||
///获取程序名字
|
||
let App_Name = Bundle.main.infoDictionary!["CFBundleDisplayName"] as! String
|
||
///获取手机型号
|
||
let Phone_Model = UIDevice.current.model
|
||
///系统版本号
|
||
let System_Version = UIDevice.current.systemVersion
|
||
///获取当前系统语言
|
||
var Language_first_local:String {
|
||
let first = Locale.preferredLanguages.first!
|
||
let languageCode = Locale(identifier: first).languageCode
|
||
if let code = languageCode {
|
||
return code
|
||
} else {
|
||
return "en"
|
||
}
|
||
}
|
||
///当前应用版本号
|
||
var app_Version:String{
|
||
if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String {
|
||
return version
|
||
}else {
|
||
return "1.0.0"
|
||
}
|
||
}
|
||
///底部安全区域
|
||
let bottomPadding = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
|
||
///全局占位图
|
||
let placeholderImage:UIImage = UIImage(named: "placeholder")!
|
||
///隐私政策网址
|
||
let privacyUrl:URL = .init(string: "https://musiclax.mystrikingly.com/privacy")!
|
||
///用户协议网址
|
||
let serviceUrl:URL = .init(string: "https://musiclax.mystrikingly.com/terms")!
|
||
|
||
//MARK: - 全局变量与方法
|
||
///总事件闭包
|
||
typealias ActionBlock = () -> Void?
|
||
///A面全局模态弹出类型
|
||
var MPSideA_ModalType:MPSideA_PresentModal = .Timer
|
||
///B面全局模态弹出类型
|
||
var MPPositive_ModalType:MPPositive_PresentModal = .PlayerList
|
||
///沙盒文件
|
||
let DocumentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||
///获取沙盒下载路径
|
||
func getDocumentsFileURL(_ videoID: String) -> String? {
|
||
// 获取Documents目录的URL
|
||
let documentsDirectoryURL = DocumentsURL.appendingPathComponent("Downloads")
|
||
// 根据videoId构建文件完整URL
|
||
let fileURL = documentsDirectoryURL.appendingPathComponent("\(videoID).mp4")
|
||
//检索是否存在
|
||
if FileManager.default.fileExists(atPath: fileURL.path) == true {
|
||
//存在
|
||
return fileURL.absoluteString
|
||
}else {
|
||
return nil
|
||
}
|
||
}
|
||
///调用next对单曲数据歌词ID与相关ID补全
|
||
func improveDataforLycirsAndRelated(_ song:MPPositive_SongItemModel, completion:@escaping(((String?,String?)) -> Void)) {
|
||
//单曲补全需要再次调用next接口
|
||
MP_NetWorkManager.shared.requestNextLyricsAndRelated(song){ result in
|
||
completion(result)
|
||
}
|
||
}
|
||
///调用player对资源路径和封面路径补全
|
||
func improveDataforResouceAndCover(_ song:MPPositive_SongItemModel, completion:@escaping((([String],[Int],[String])?, [String]?) -> Void)) {
|
||
//单曲补全需要调用player接口
|
||
MP_NetWorkManager.shared.requestAndroidPlayer(song.videoId, playlistId: "") { resourceUrls, coverUrls in
|
||
completion(resourceUrls,coverUrls)
|
||
}
|
||
}
|
||
///转时分值
|
||
func setTimesToMinSeconds(_ time:TimeInterval) -> String {
|
||
//设置分钟
|
||
let min = Int((time.isNaN ? 0:time) / 60)
|
||
let second = Int((time.isNaN ? 0:time).truncatingRemainder(dividingBy: 60))
|
||
return "\(min < 10 ? "0\(min)":"\(min)"):\(second < 10 ? "0\(second)":"\(second)")"
|
||
}
|
||
///转分值
|
||
func setTimesToMins(_ time:TimeInterval) -> String {
|
||
//设置分钟
|
||
let min = Int((time.isNaN ? 0:time) / 60)
|
||
return "\(min < 10 ? "0\(min)":"\(min)")"
|
||
}
|
||
///获取麦克风权限
|
||
func authorize(observe:UIViewController) -> Bool{
|
||
let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)
|
||
switch status {
|
||
case .authorized:
|
||
return true
|
||
case .notDetermined:
|
||
// 请求授权
|
||
AVCaptureDevice.requestAccess(for: AVMediaType.audio, completionHandler: {(status) in
|
||
DispatchQueue.main.async(execute: {() -> Void in
|
||
_ = authorize(observe: observe)
|
||
})
|
||
})
|
||
default: ()
|
||
DispatchQueue.main.async(execute: { () -> Void in
|
||
let alertController = UIAlertController(title: "Get Microphone Access",message: "“Musiclax” asks you to turn on your microphone to recognize the decibels around you and turns on white noise for you automatically. Please go to the “Settings” page to turn on the microphone permission",preferredStyle: .alert)
|
||
let cancelAction = UIAlertAction(title:"Cancel", style: .cancel, handler:nil)
|
||
let settingsAction = UIAlertAction(title:"Settings", style: .default, handler: {
|
||
(action) -> Void in
|
||
let url = URL(string: UIApplication.openSettingsURLString)
|
||
if let url = url, UIApplication.shared.canOpenURL(url) {
|
||
if #available(iOS 10, *) {
|
||
UIApplication.shared.open(url, options: [:],
|
||
completionHandler: {
|
||
(success) in
|
||
})
|
||
} else {
|
||
UIApplication.shared.openURL(url)
|
||
}
|
||
}
|
||
})
|
||
alertController.addAction(cancelAction)
|
||
alertController.addAction(settingsAction)
|
||
observe.present(alertController, animated: true)
|
||
})
|
||
}
|
||
return false
|
||
}
|
||
///创建一个Label
|
||
func createLabel(_ text:String? = nil, font:UIFont, textColor:UIColor, textAlignment:NSTextAlignment, lines:Int = 1) -> UILabel {
|
||
let label = UILabel()
|
||
label.text = text ?? "text"
|
||
label.font = font
|
||
label.textColor = textColor
|
||
label.textAlignment = textAlignment
|
||
label.numberOfLines = lines
|
||
return label
|
||
}
|
||
///根据播放器状态将按钮的图片进行切换
|
||
func switchPlayTypeBtnIcon(_ btn:UIButton) {
|
||
switch MP_PlayerManager.shared.getPlayType() {
|
||
case .normal://列表播放图案
|
||
btn.setBackgroundImage(UIImage(named: "List_NormolPlay'logo"), for: .normal)
|
||
case .random://随机播放图案
|
||
btn.setBackgroundImage(UIImage(named: "Player_Shuffle'logo"), for: .normal)
|
||
case .single://单曲循环图案
|
||
btn.setBackgroundImage(UIImage(named: "Player_Single'logo"), for: .normal)
|
||
}
|
||
}
|
||
///请求广告授权
|
||
func requestTrackingAuthorization(completion: @escaping (String?) -> Void) {
|
||
if #available(iOS 14, *) {
|
||
var attemptsLeft = 3
|
||
|
||
func requestAuth() {
|
||
ATTrackingManager.requestTrackingAuthorization { status in
|
||
switch status {
|
||
case .authorized:
|
||
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
||
print("Authorized: IDFA = \(idfa)")
|
||
completion(idfa)
|
||
case .denied, .restricted:
|
||
print("Denied or Restricted")
|
||
completion(nil)
|
||
case .notDetermined:
|
||
print("Not Determined")
|
||
attemptsLeft -= 1
|
||
if attemptsLeft > 0 {
|
||
requestAuth() // 继续请求直到达到最大尝试次数
|
||
} else {
|
||
print("Reached maximum number of attempts")
|
||
completion(nil)
|
||
}
|
||
@unknown default:
|
||
print("Unknown status")
|
||
completion(nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
requestAuth() // 第一次请求
|
||
} else {
|
||
if ASIdentifierManager.shared().isAdvertisingTrackingEnabled {
|
||
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
||
print("Tracking enabled: IDFA = \(idfa)")
|
||
completion(idfa)
|
||
} else {
|
||
print("Tracking not enabled")
|
||
completion(nil)
|
||
}
|
||
}
|
||
}
|
||
///截取\n\n后续的文本
|
||
func truncateTextAfterTwoNewlines(from text: String) -> String {
|
||
// 定义正则表达式,匹配两个连续的换行符及其之后的内容
|
||
let pattern = "\n{2,}.*"
|
||
let regex = try! NSRegularExpression(pattern: pattern, options: [.dotMatchesLineSeparators])
|
||
|
||
// 使用正则表达式进行替换,删除匹配到的部分
|
||
let truncatedText = regex.stringByReplacingMatches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count), withTemplate: "")
|
||
|
||
return truncatedText
|
||
}
|
||
///获取通知请求权限
|
||
func getUserNotificationCenter() {
|
||
//请求通知权限
|
||
UNUserNotificationCenter.current()
|
||
.requestAuthorization(options: [.alert, .sound, .badge]) {
|
||
(accepted, error) in
|
||
if !accepted {
|
||
print("Users are not allowed to be notified of messages.")
|
||
}
|
||
}
|
||
}
|