1.3.4小问题修正版

This commit is contained in:
Mr.zhou 2024-12-25 10:02:00 +08:00
parent 16343bff6f
commit b4e9cfc1e8
24 changed files with 476 additions and 370 deletions

View File

@ -14,6 +14,7 @@
CB0033F62C295E3100B18FD3 /* MPPositive_MoreOperationShowTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0033F52C295E3100B18FD3 /* MPPositive_MoreOperationShowTableViewCell.swift */; };
CB0033F82C29626900B18FD3 /* MPPositive_ChoosePlayListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0033F72C29626900B18FD3 /* MPPositive_ChoosePlayListViewController.swift */; };
CB0033FC2C29753D00B18FD3 /* MPPositive_PlayListMoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0033FB2C29753D00B18FD3 /* MPPositive_PlayListMoreViewController.swift */; };
CB091A202D1A5B070015BF62 /* MPPositive_DefaultTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB091A1F2D1A5B070015BF62 /* MPPositive_DefaultTableView.swift */; };
CB0968752C2121410045E55B /* GADTSmallTemplateView.m in Sources */ = {isa = PBXBuildFile; fileRef = CB09686C2C2121410045E55B /* GADTSmallTemplateView.m */; };
CB0968762C2121410045E55B /* GADTSmallTemplateView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CB09686D2C2121410045E55B /* GADTSmallTemplateView.xib */; };
CB0968772C2121410045E55B /* GADTTemplateView.m in Sources */ = {isa = PBXBuildFile; fileRef = CB09686F2C2121410045E55B /* GADTTemplateView.m */; };
@ -37,6 +38,7 @@
CB51340E2C9C1E4800833AD5 /* MP_ADSimpleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB51340D2C9C1E4800833AD5 /* MP_ADSimpleManager.swift */; };
CB6EEB8E2C5DFE6100AEC414 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB6EEB8D2C5DFE6100AEC414 /* StoreKit.framework */; };
CB7FC5482C2AC25C00292A43 /* MPPositive_CenterListSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB7FC5472C2AC25C00292A43 /* MPPositive_CenterListSearchView.swift */; };
CB8D21982D196F51001D8DB8 /* MPPositive_BatchDeletionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB8D21972D196F51001D8DB8 /* MPPositive_BatchDeletionViewController.swift */; };
CBAFCAE62C0A10500054500E /* MP_BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBAFC9F22C0A10500054500E /* MP_BaseViewController.swift */; };
CBAFCAE72C0A10500054500E /* MP_LunchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBAFC9F32C0A10500054500E /* MP_LunchViewController.swift */; };
CBAFCAE82C0A10500054500E /* MP_LunchViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBAFC9F42C0A10500054500E /* MP_LunchViewController.xib */; };
@ -238,9 +240,6 @@
CBB720542C6A040000D1B504 /* MP_IAPViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBB720532C6A040000D1B504 /* MP_IAPViewController.xib */; };
CBB75FDD2C4F7AA60041665D /* UIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB75FDC2C4F7AA60041665D /* UIImageView.swift */; };
CBBAF8CD2C339CF200B3C838 /* MPPositive_JsonCharts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBBAF8CC2C339CF200B3C838 /* MPPositive_JsonCharts.swift */; };
CBBE53382CF065800036D2D9 /* FacebookAEM in Frameworks */ = {isa = PBXBuildFile; productRef = CBBE53372CF065800036D2D9 /* FacebookAEM */; };
CBBE533A2CF065800036D2D9 /* FacebookBasics in Frameworks */ = {isa = PBXBuildFile; productRef = CBBE53392CF065800036D2D9 /* FacebookBasics */; };
CBBE533C2CF065800036D2D9 /* FacebookCore in Frameworks */ = {isa = PBXBuildFile; productRef = CBBE533B2CF065800036D2D9 /* FacebookCore */; };
CBBFD8212C8018D100BD67BC /* Reload_Animation.json in Resources */ = {isa = PBXBuildFile; fileRef = CBBFD8202C8018D100BD67BC /* Reload_Animation.json */; };
CBC1FB7A2C50999800AC0633 /* MPPositive_LibraryItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC1FB792C50999800AC0633 /* MPPositive_LibraryItemModel.swift */; };
CBC1FB7C2C509B7300AC0633 /* MPPositive_LibraryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC1FB7B2C509B7300AC0633 /* MPPositive_LibraryViewModel.swift */; };
@ -271,6 +270,9 @@
CBDBDDF42C40D03F00767F0B /* MPPositive_SearchGrideCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDBDDF32C40D03F00767F0B /* MPPositive_SearchGrideCollectionViewCell.swift */; };
CBDBDDF62C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDBDDF52C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift */; };
CBDC4A292C61B88300960649 /* relax.offline.mp3.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CBDC4A272C61B88300960649 /* relax.offline.mp3.xcdatamodeld */; };
CBDFD6C02D153B6400009948 /* FacebookAEM in Frameworks */ = {isa = PBXBuildFile; productRef = CBDFD6BF2D153B6400009948 /* FacebookAEM */; };
CBDFD6C22D153B6400009948 /* FacebookBasics in Frameworks */ = {isa = PBXBuildFile; productRef = CBDFD6C12D153B6400009948 /* FacebookBasics */; };
CBDFD6C42D153B6400009948 /* FacebookCore in Frameworks */ = {isa = PBXBuildFile; productRef = CBDFD6C32D153B6400009948 /* FacebookCore */; };
CBEC78BF2CA28FB700666A7F /* MPPositive_AddSongsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBEC78BE2CA28FB700666A7F /* MPPositive_AddSongsViewController.swift */; };
CBEC78C12CA2963100666A7F /* MPPositive_AddSongsShowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBEC78C02CA2963100666A7F /* MPPositive_AddSongsShowView.swift */; };
CBEC78C32CA2A0CB00666A7F /* MPPositive_AddSongTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBEC78C22CA2A0CB00666A7F /* MPPositive_AddSongTableViewCell.swift */; };
@ -288,6 +290,7 @@
CB0033F52C295E3100B18FD3 /* MPPositive_MoreOperationShowTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_MoreOperationShowTableViewCell.swift; sourceTree = "<group>"; };
CB0033F72C29626900B18FD3 /* MPPositive_ChoosePlayListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_ChoosePlayListViewController.swift; sourceTree = "<group>"; };
CB0033FB2C29753D00B18FD3 /* MPPositive_PlayListMoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_PlayListMoreViewController.swift; sourceTree = "<group>"; };
CB091A1F2D1A5B070015BF62 /* MPPositive_DefaultTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_DefaultTableView.swift; sourceTree = "<group>"; };
CB09686B2C2121410045E55B /* GADTSmallTemplateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GADTSmallTemplateView.h; sourceTree = "<group>"; };
CB09686C2C2121410045E55B /* GADTSmallTemplateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GADTSmallTemplateView.m; sourceTree = "<group>"; };
CB09686D2C2121410045E55B /* GADTSmallTemplateView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GADTSmallTemplateView.xib; sourceTree = "<group>"; };
@ -320,6 +323,7 @@
CB51340D2C9C1E4800833AD5 /* MP_ADSimpleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_ADSimpleManager.swift; sourceTree = "<group>"; };
CB6EEB8D2C5DFE6100AEC414 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
CB7FC5472C2AC25C00292A43 /* MPPositive_CenterListSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CenterListSearchView.swift; sourceTree = "<group>"; };
CB8D21972D196F51001D8DB8 /* MPPositive_BatchDeletionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_BatchDeletionViewController.swift; sourceTree = "<group>"; };
CBAFC9F22C0A10500054500E /* MP_BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MP_BaseViewController.swift; sourceTree = "<group>"; };
CBAFC9F32C0A10500054500E /* MP_LunchViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MP_LunchViewController.swift; sourceTree = "<group>"; };
CBAFC9F42C0A10500054500E /* MP_LunchViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MP_LunchViewController.xib; sourceTree = "<group>"; };
@ -583,9 +587,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CBBE533A2CF065800036D2D9 /* FacebookBasics in Frameworks */,
CBBE533C2CF065800036D2D9 /* FacebookCore in Frameworks */,
CBBE53382CF065800036D2D9 /* FacebookAEM in Frameworks */,
CBDFD6C22D153B6400009948 /* FacebookBasics in Frameworks */,
CBDFD6C42D153B6400009948 /* FacebookCore in Frameworks */,
CBDFD6C02D153B6400009948 /* FacebookAEM in Frameworks */,
CBAFCBAD2C0A10DA0054500E /* FirebaseCrashlytics in Frameworks */,
CBD4570D2C2EC38400CE766D /* AppTrackingTransparency.framework in Frameworks */,
CBAFCBAB2C0A10DA0054500E /* FirebaseAnalytics in Frameworks */,
@ -937,6 +941,7 @@
CBAFCA682C0A10500054500E /* MPPositive_LoveSongsViewController.swift */,
CBAFCA672C0A10500054500E /* MPPositive_LoveArtistsViewController.swift */,
CBAFCA692C0A10500054500E /* MPPositive_OfflineSongsViewController.swift */,
CB8D21972D196F51001D8DB8 /* MPPositive_BatchDeletionViewController.swift */,
);
path = "Center个人曲库页";
sourceTree = "<group>";
@ -991,6 +996,7 @@
CBAFCA7B2C0A10500054500E /* MPPositive_CustomTabBarView.swift */,
CBAFCA7A2C0A10500054500E /* MPPositive_CustomTabBarItem.swift */,
CBAFCA782C0A10500054500E /* MPPositive_BottomShowView.swift */,
CB091A1F2D1A5B070015BF62 /* MPPositive_DefaultTableView.swift */,
CBAFCA7C2C0A10500054500E /* MPPositive_MoreOperationDownLoadTableViewCell.swift */,
CB0033F52C295E3100B18FD3 /* MPPositive_MoreOperationShowTableViewCell.swift */,
CB0B36902C65EBFC004036E2 /* MPPositive_BaseShowView.swift */,
@ -1323,9 +1329,9 @@
CBAFCBAC2C0A10DA0054500E /* FirebaseCrashlytics */,
CBAFCBAE2C0A10DA0054500E /* FirebaseRemoteConfig */,
CB0B368A2C65AE3A004036E2 /* Lottie */,
CBBE53372CF065800036D2D9 /* FacebookAEM */,
CBBE53392CF065800036D2D9 /* FacebookBasics */,
CBBE533B2CF065800036D2D9 /* FacebookCore */,
CBDFD6BF2D153B6400009948 /* FacebookAEM */,
CBDFD6C12D153B6400009948 /* FacebookBasics */,
CBDFD6C32D153B6400009948 /* FacebookCore */,
);
productName = relax.offline.mp3.music;
productReference = CBC2D6E82BFDF3D700E17703 /* relax.offline.mp3.music.app */;
@ -1365,7 +1371,7 @@
packageReferences = (
CBAFCBA92C0A10DA0054500E /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
CB0B36892C65AE3A004036E2 /* XCRemoteSwiftPackageReference "lottie-spm" */,
CBBE53362CF065800036D2D9 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */,
CBDFD6BE2D153B6400009948 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */,
);
productRefGroup = CBC2D6E92BFDF3D700E17703 /* Products */;
projectDirPath = "";
@ -1528,6 +1534,7 @@
CB1182932CA8EF5A00BAEDC0 /* MP_DownloadButton.swift in Sources */,
CBD344DE2C3FD8230095F18F /* MPPositive_GridViewModel.swift in Sources */,
CBAFCB622C0A10500054500E /* MPPositive_HomeListFirstCollectionViewCell.swift in Sources */,
CB091A202D1A5B070015BF62 /* MPPositive_DefaultTableView.swift in Sources */,
CBC5E51D2C7D82A200336746 /* MPPositive_RecentlyModel.swift in Sources */,
CBAFCB112C0A10500054500E /* MP_PlayerManager.swift in Sources */,
CBDC4A292C61B88300960649 /* relax.offline.mp3.xcdatamodeld in Sources */,
@ -1538,6 +1545,7 @@
CBAFCB782C0A10500054500E /* MPSideA_MusicViewModel.swift in Sources */,
CBAFCB642C0A10500054500E /* MPPositive_HomeListSecondCollectionViewCell.swift in Sources */,
CBAFCB0A2C0A10500054500E /* MP_CacheManager.swift in Sources */,
CB8D21982D196F51001D8DB8 /* MPPositive_BatchDeletionViewController.swift in Sources */,
CBAFCB892C0A10500054500E /* MPSideA_RenameViewController.swift in Sources */,
CBAFCB632C0A10500054500E /* MPPositive_HomeListFourthCollectionViewCell.swift in Sources */,
CB1E3B682C23E09100071DEA /* MPPositive_CustomVideoModel.swift in Sources */,
@ -2050,12 +2058,12 @@
minimumVersion = 10.27.0;
};
};
CBBE53362CF065800036D2D9 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = {
CBDFD6BE2D153B6400009948 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/facebook/facebook-ios-sdk";
requirement = {
kind = exactVersion;
version = 17.1.0;
kind = upToNextMajorVersion;
minimumVersion = 14.1.0;
};
};
/* End XCRemoteSwiftPackageReference section */
@ -2081,19 +2089,19 @@
package = CBAFCBA92C0A10DA0054500E /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseRemoteConfig;
};
CBBE53372CF065800036D2D9 /* FacebookAEM */ = {
CBDFD6BF2D153B6400009948 /* FacebookAEM */ = {
isa = XCSwiftPackageProductDependency;
package = CBBE53362CF065800036D2D9 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
package = CBDFD6BE2D153B6400009948 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
productName = FacebookAEM;
};
CBBE53392CF065800036D2D9 /* FacebookBasics */ = {
CBDFD6C12D153B6400009948 /* FacebookBasics */ = {
isa = XCSwiftPackageProductDependency;
package = CBBE53362CF065800036D2D9 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
package = CBDFD6BE2D153B6400009948 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
productName = FacebookBasics;
};
CBBE533B2CF065800036D2D9 /* FacebookCore */ = {
CBDFD6C32D153B6400009948 /* FacebookCore */ = {
isa = XCSwiftPackageProductDependency;
package = CBBE53362CF065800036D2D9 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
package = CBDFD6BE2D153B6400009948 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
productName = FacebookCore;
};
/* End XCSwiftPackageProductDependency section */

View File

@ -24,8 +24,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/facebook/facebook-ios-sdk",
"state" : {
"revision" : "3cebc3b1d13dbe85868cc04f5bed63648e8c410c",
"version" : "17.1.0"
"revision" : "c19607d535864533523d1f437c84035e5fb101cf",
"version" : "14.1.0"
}
},
{

View File

@ -34,13 +34,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var backgroundTask: UIBackgroundTaskIdentifier = .invalid
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(accepted, error) in
if !accepted {
print("Users are not allowed to be notified of messages.")
}
}
//
if let notificationData = launchOptions?[.remoteNotification] as? [String: AnyObject] {
MP_AnalyticsManager.shared.handle_notificationAction()
}
//
UNUserNotificationCenter.current().delegate = notificationHandler
//广ID
@ -61,6 +64,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
//faceBook
ApplicationDelegate.shared.application(application,didFinishLaunchingWithOptions: launchOptions)
Settings.shared.isAdvertiserIDCollectionEnabled = true
//
MP_IAPManager.shared.observeVIPStoreKit()
MP_IAPManager.shared.getVIPAllProducts()
switch_lunch()
//
MP_AnalyticsManager.shared.user_launchAction()
@ -288,13 +294,26 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
let accessAppdelegate = ( UIApplication.shared.delegate as! AppDelegate)
///
class NotificationHandler: NSObject, UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void) {
//
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
// options completionHandler:
// completionHandler([])
}
//
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let content = response.notification.request.content
let userInfo = content.userInfo //
switch response.actionIdentifier {
case UNNotificationDefaultActionIdentifier:
//
print("用户点击了通知: \(content.title), \(content.body)")
MP_AnalyticsManager.shared.handle_notificationAction()
case UNNotificationDismissActionIdentifier:
//
print("用户忽略了通知")
default:
//
print("用户点击了自定义按钮: \(response.actionIdentifier)")
}
completionHandler()
}
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "delete@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "delete@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Restor@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Restor@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Upgrade@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Upgrade@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -116,9 +116,6 @@ class MP_LunchViewController: UIViewController {
private func switchAOrBAction() {
//B
guard UserDefaults.standard.bool(forKey: "MP_Into_B") != true else {
//
MP_IAPManager.shared.observeVIPStoreKit()
MP_IAPManager.shared.getVIPAllProducts()
loadAds()
//
MP_AnalyticsManager.shared.getOpenStatus(0) { open in
@ -156,9 +153,6 @@ class MP_LunchViewController: UIViewController {
MP_NetWorkManager.shared.performTaskNetWrokAvailable {
[weak self] in
guard let self = self else {return}
//
MP_IAPManager.shared.observeVIPStoreKit()
MP_IAPManager.shared.getVIPAllProducts()
//广
loadAds()
//

View File

@ -59,7 +59,7 @@ class MP_ADSimpleManager: NSObject {
}
}
///使广
var internalAdStatus:Bool = true
var internalAdStatus:Bool = false
///广
func setOpenAdStatus(_ bool:Bool) {
DispatchQueue.main.async {

View File

@ -107,6 +107,8 @@ class MP_AnalyticsManager: NSObject {
private let update_reminder_cancel = "update_reminder_cancel"
///
private let update_reminder_sure = "update_reminder_sure"
///
private let handle_notification = "handle_notification"
private override init() {
//
if UserDefaults.standard.bool(forKey: "UserStatus") {
@ -333,9 +335,19 @@ class MP_AnalyticsManager: NSObject {
func config_success_eventAction() {
Analytics.logEvent(config_success_event, parameters: ["USER_STATU":isOLD ? "Old":"New"])
}
///
///
/// - Parameters:
/// - showAd: 广
func launch_progress_endAction(_ showAd:String) {
Analytics.logEvent(launch_progress_end, parameters: ["USER_STATU":isOLD ? "Old":"New","showAd":showAd])
var statu:String = ""
if MP_NetWorkManager.shared.netWorkStatu == .reachable {
//
statu = "Yes"
}else {
statu = "No"
}
Analytics.logEvent(launch_progress_end, parameters: ["USER_STATU":isOLD ? "Old":"New","showAd":showAd, "network":statu])
}
///
func jump_eventAction(_ side:String, reason:String) {
@ -588,6 +600,10 @@ class MP_AnalyticsManager: NSObject {
func update_reminder_cancelAction() {
Analytics.logEvent(update_reminder_cancel, parameters: ["USER_STATU":isOLD ? "Old":"New"])
}
///
func handle_notificationAction() {
Analytics.logEvent(handle_notification, parameters: nil)
}
//MARK: - 广
//
private let cold_ads_chance:String = "cold_ads_chance"

View File

@ -24,9 +24,14 @@ class MP_IAPManager: NSObject {
private var showHUD:Bool = false
///VIP
var isVIP:Bool {
//VIP
guard let lastDate = UserDefaults.standard.object(forKey: "PurchaseVIPDate") as? Date, lastDate.timeIntervalSince(Date()) > 0 else { return false }
return true
if let purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String], !purchasedProducts.isEmpty {
//VIP
return true
}else {
//VIP
guard let lastDate = UserDefaults.standard.object(forKey: "PurchaseVIPDate") as? Date, lastDate.timeIntervalSince(Date()) > 0 else { return false }
return true
}
}
override init() {
@ -38,8 +43,6 @@ class MP_IAPManager: NSObject {
}
///
func observeVIPStoreKit() {
//
// guard
//
transactions.removeAll()
//
@ -47,6 +50,7 @@ class MP_IAPManager: NSObject {
guard let self = self else { return }
var productId = ""
//
print("检索交易")
purchases.forEach { item in
switch item.transaction.transactionState {
case .purchased, .restored:///
@ -78,6 +82,9 @@ class MP_IAPManager: NSObject {
print("当前用户非VIP")
}
}
if let purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String], !purchasedProducts.isEmpty {
restorePurchases(true)
}
}
///
func getVIPAllProducts() {
@ -108,9 +115,13 @@ class MP_IAPManager: NSObject {
}
///
func restorePurchases() {
MP_HUD.loading()
showHUD = true
func restorePurchases(_ isLaunch:Bool = false) {
if isLaunch == true {
showHUD = false
}else {
MP_HUD.loading()
showHUD = true
}
self.transactions.removeAll()
SwiftyStoreKit.restorePurchases(atomically: false) { [weak self] results in
guard let self = self else { return }
@ -128,33 +139,7 @@ class MP_IAPManager: NSObject {
}
}
// ///广
// func startLunchStatus() {
// //
// let receiptURL = Bundle.main.appStoreReceiptURL
// guard let receipt = try? Data(contentsOf: receiptURL!) else {
// //
// print("广")
// //AppStore,使广
// MP_ADSimpleManager.shared.setOpenAdStatus(true)
// return
// }
// //
// print("")
// reloadOpenStatus()
// }
//
// ///广
// func reloadOpenStatus() {
// //广
// if isProductPurchased(productId: productIdentifiers[0]) || isProductPurchased(productId: productIdentifiers[1]) || isProductPurchased(productId: productIdentifiers[2]){
// //广
// MP_ADSimpleManager.shared.setOpenAdStatus(false)
// }else {
// MP_ADSimpleManager.shared.setOpenAdStatus(true)
// }
// }
}
//MARK: -
@ -226,6 +211,11 @@ extension MP_IAPManager {
self.showFailedHUD()
}
}
//
if let purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String], !purchasedProducts.isEmpty {
print("清理旧版VIP信息")
UserDefaults.standard.set(nil, forKey: "PurchasedProducts")
}
case .error(let error)://
self.finishedAllTransactionsVIP()
self.showFailedHUD()
@ -262,254 +252,3 @@ extension MP_IAPManager {
}
}
//MARK: - SKProductsRequestDelegate
//extension MP_IAPManager: SKProductsRequestDelegate, SKPaymentTransactionObserver {
// ///
// func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
// //
// availableProducts = response.products
// //
// guard availableProducts.isEmpty == false else {
// //
// print("")
// return
// }
// //,
// for (index, item) in availableProducts.enumerated() {
// print("\(index)--\(item)")
// }
// }
// ///
// func request(_ request: SKRequest, didFailWithError error: any Error) {
// print("Failed to fetch products: \(error.localizedDescription)")
// }
// ///
// func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
// //
// transactions.forEach { item in
// //
// switch item.transactionState {
// case .purchasing://
// break
// case .purchased://
// complete(transaction: item)
// case .failed://
// fail(transaction: item)
// case .restored://
// restore(transaction: item)
// case .deferred://
// break
// @unknown default:
// break
// }
// }
// }
// ///
// func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
// print("")
// MP_HUD.hideNow()
// //
// if queue.transactions.isEmpty {
// //ID
// print("/")
// productIdentifiers.forEach { item in
// cleanPurchase(productId: item)
// }
// MP_ADSimpleManager.shared.setOpenAdStatus(true)
// }
// }
// func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: any Error) {
// print("")
// MP_HUD.error("The current transaction failed".localizableString(), delay: 1.0, completion: nil)
// //VIP
// productIdentifiers.forEach { item in
// cleanPurchase(productId: item)
// }
// MP_ADSimpleManager.shared.setOpenAdStatus(true)
// }
// //
// private func storePurchase(productId: String) {
// if isProductPurchased(productId: productId) == false {
// var purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String] ?? []
// purchasedProducts.append(productId)
// UserDefaults.standard.set(purchasedProducts, forKey: "PurchasedProducts")
// }
// }
// //VIP
// private func isProductPurchased(productId: String) -> Bool {
// let purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String] ?? []
// return purchasedProducts.contains(productId)
// }
// //广ID
// private func cleanPurchase(productId: String) {
// if isProductPurchased(productId: productId) {
// var purchasedProducts = UserDefaults.standard.array(forKey: "PurchasedProducts") as? [String] ?? []
// purchasedProducts.removeAll(where: {$0 == productId})
// UserDefaults.standard.set(purchasedProducts, forKey: "PurchasedProducts")
// }
// }
// ///
// private func complete(transaction: SKPaymentTransaction) {
// MP_HUD.success("Successfully purchased", delay: 1.0, completion: nil)
// print("Transaction completed successfully.")
// MP_AnalyticsManager.shared.VIP_buy_successAction(transaction.payment.productIdentifier)
// validateReceipt { [weak self] status in
// guard let self = self else {return}
// if status {
// //
// self.storePurchase(productId: transaction.payment.productIdentifier)
// SKPaymentQueue.default().finishTransaction(transaction)
// //广
// reloadOpenStatus()
// }
// }
// }
// //
// private func restore(transaction: SKPaymentTransaction) {
// print("Transaction restored.")
// validateReceipt { [weak self] status in
// guard let self = self else {return}
// if status {
// //
// self.storePurchase(productId: transaction.payment.productIdentifier)
// SKPaymentQueue.default().finishTransaction(transaction)
// //广
// reloadOpenStatus()
// }
// }
// }
// ///
// private func fail(transaction: SKPaymentTransaction) {
// //
// if let error = transaction.error as NSError? {
// MP_AnalyticsManager.shared.VIP_buy_failureAction(transaction.payment.productIdentifier, error: error.localizedDescription)
// if error.code != SKError.paymentCancelled.rawValue {
// MP_HUD.error("The current transaction failed".localizableString(), delay: 1.0, completion: nil)
// } else {
// MP_HUD.onlytext("The current transaction has been canceled".localizableString(), delay: 1.0, completion: nil)
// }
// }
// }
// //
// func fetchReceipt() -> String? {
// guard let receiptURL = Bundle.main.appStoreReceiptURL else { return nil }
// guard let receiptData = try? Data(contentsOf: receiptURL) else { return nil }
// return receiptData.base64EncodedString(options: [])
// }
// //
// func validateReceipt(completion: @escaping (Bool) -> Void) {
// guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
// completion(false)
// return
// }
// //
// guard let receiptString = fetchReceipt() else {
// completion(false)
// return
// }
// //
// let requestDictionary = ["receipt-data": receiptString,
// "password": "d29627e4f78b4b50a0ce5166acd8aa9f" ]
// guard JSONSerialization.isValidJSONObject(requestDictionary) else {
// completion(false)
// return
// }
//
// do {
// let requestData = try JSONSerialization.data(withJSONObject: requestDictionary)
// #if DEBUG
// let validationURLString = "https://sandbox.itunes.apple.com/verifyReceipt"
// #else
// let validationURLString = "https://buy.itunes.apple.com/verifyReceipt"
// #endif
// guard let validationURL = URL(string: validationURLString) else {
// completion(false)
// return
// }
// //
// var request = URLRequest(url: validationURL)
// request.httpMethod = "POST"
// request.cachePolicy = .reloadIgnoringCacheData
// request.httpBody = requestData
// //
// let session = URLSession.shared
// //
// let task = session.dataTask(with: request) { data, response, error in
// guard error == nil, let data = data else {
// completion(false)
// return
// }
//
// do {
// if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
// if let status = jsonResponse["status"] as? Int {
// if status == 0 {
// completion(true)
// } else if status == 21007 {
// self.validateReceiptInSandbox(receiptString: receiptString, completion: completion)
// } else {
// print("Receipt validation failed with status: \(status)")
// completion(false)
// }
// } else {
// completion(false)
// }
// } else {
// completion(false)
// }
// } catch {
// completion(false)
// }
// }
// task.resume()
// } catch {
// completion(false)
// }
// }
// func validateReceiptInSandbox(receiptString: String, completion: @escaping (Bool) -> Void) {
// let requestDictionary = ["receipt-data": receiptString,
// "password": "d29627e4f78b4b50a0ce5166acd8aa9f"]
// guard JSONSerialization.isValidJSONObject(requestDictionary) else {
// completion(false)
// return
// }
//
// do {
// let requestData = try JSONSerialization.data(withJSONObject: requestDictionary)
// let validationURLString = "https://sandbox.itunes.apple.com/verifyReceipt"
// guard let validationURL = URL(string: validationURLString) else {
// completion(false)
// return
// }
//
// var request = URLRequest(url: validationURL)
// request.httpMethod = "POST"
// request.cachePolicy = .reloadIgnoringCacheData
// request.httpBody = requestData
//
// let session = URLSession.shared
// let task = session.dataTask(with: request) { data, response, error in
// guard error == nil, let data = data else {
// completion(false)
// return
// }
// do {
// if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
// if let status = jsonResponse["status"] as? Int, status == 0 {
// completion(true)
// } else {
// completion(false)
// }
// } else {
// completion(false)
// }
// } catch {
// completion(false)
// }
// }
// task.resume()
// } catch {
// completion(false)
// }
// }
//}

View File

@ -27,15 +27,21 @@ class MPPositive_CustomPlayListModel: NSManagedObject, MP_CoreDataManageableDele
extension MPPositive_CustomPlayListModel {
///videos[MPPositive_CustomVideoModel]
var videosArray:[MPPositive_CustomVideoModel]{
guard let context = self.managedObjectContext else { return [] }
// Core Data 访
self.willAccessValue(forKey: "videos")
let set = (videos as? Set<MPPositive_CustomVideoModel>)?.compactMap { $0 } ?? []
guard let set = (self.videos as? Set<MPPositive_CustomVideoModel>) else {
// Core Data 访
self.didAccessValue(forKey: "videos")
return []
}
// Core Data 访
self.didAccessValue(forKey: "videos")
//
let array = Array(set).sorted { item1, item2 in
return (item1.addTime ?? .init()) > (item2.addTime ?? .init())
let time1 = item1.addTime ?? .distantPast
let time2 = item2.addTime ?? .distantPast
return time1 > time2
}
return array
}

View File

@ -0,0 +1,113 @@
//
// MPPositive_BatchDeletionViewController.swift
// relax.offline.mp3.music
//
// Created by Mr.Zhou on 2024/12/23.
//
import UIKit
///
class MPPositive_BatchDeletionViewController: MPPositive_BaseViewController {
//
private lazy var confirmBtn:UIButton = {
let btn:UIButton = .init()
btn.setTitle("Confirm", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 16*width, weight: .medium)
btn.addTarget(self, action: #selector(deleteAction(_ :)), for: .touchUpInside)
return btn
}()
//tableView
private lazy var tableView:MPPositive_DefaultTableView = {
let tableView:MPPositive_DefaultTableView = .init(frame: .zero, style: .plain)
tableView.dataSource = self
tableView.delegate = self
tableView.register(MPPositive_AddSongTableViewCell.self, forCellReuseIdentifier: MPPositive_AddSongTableViewCellID)
return tableView
}()
private let MPPositive_AddSongTableViewCellID = "MPPositive_AddSongTableViewCell"
private var status:[Bool] = []
private var offlines:[MPPositive_DownloadViewModel]
init(withOfflines offlines:[MPPositive_DownloadViewModel]) {
self.offlines = offlines
super.init(nibName: nil, bundle: nil)
refreshStatus()
}
required init?(coder: NSCoder) {
self.offlines = []
super.init(coder: coder)
refreshStatus()
}
override func viewDidLoad() {
super.viewDidLoad()
setPopBtn()
setTitle("Batch Deletion")
config()
}
private func config() {
navView.addSubview(confirmBtn)
confirmBtn.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-16*width)
make.centerY.equalToSuperview()
}
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.left.bottom.right.equalToSuperview()
make.top.equalTo(navView.snp.bottom)
}
}
//status
private func refreshStatus() {
//线(false)
self.status = offlines.compactMap({_ in false})
//
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
tableView.showMessage(status.count)
tableView.reloadData()
}
}
//
@objc private func deleteAction(_ sender:UIButton) {
view.endEditing(true)
//ture
var array:[MPPositive_DownloadViewModel] = []
for (index, item) in status.enumerated() {
if item == true {
array.append(offlines[index])
}
}
guard !array.isEmpty else {
MP_HUD.showWithStatus(hudStatus: .error, text: "Please select the song", delay: 1.0, completion: nil)
return
}
MP_HUD.loading()
array.forEach { item in
//
MP_DownloadManager.shared.deleteFileDocuments(item.loadItem.videoId ?? "") { videoId in
}
}
MP_HUD.success("Removed".localizableString(), delay: 1.0) { [weak self] in
self?.navigationController?.popViewController(animated: true)
}
}
}
//MARK: - tableView
extension MPPositive_BatchDeletionViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return offlines.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_AddSongTableViewCellID, for: indexPath) as! MPPositive_AddSongTableViewCell
cell.download = offlines[indexPath.row]
cell.statu = status[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//
status[indexPath.row] = !status[indexPath.row]
tableView.reloadData()
}
}

View File

@ -75,6 +75,16 @@ class MPPositive_OfflineSongsViewController: MPPositive_BaseViewController {
btn.addTarget(self, action: #selector(shuffleClick(_ :)), for: .touchUpInside)
return btn
}()
///
private lazy var bulkDeleteBtn:UIButton = {
let btn = UIButton()
btn.setImage(UIImage(named: "Center_BulkDelete'logo"), for: .normal)
btn.setTitle(" Delete", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 14*width, weight: .regular)
btn.addTarget(self, action: #selector(batchDeleteClick(_ :)), for: .touchUpInside)
return btn
}()
///
private lazy var searchBtn:UIButton = {
let btn = UIButton()
@ -275,6 +285,11 @@ class MPPositive_OfflineSongsViewController: MPPositive_BaseViewController {
make.left.equalTo(playAllBtn.snp.right).offset(18*width)
make.centerY.equalTo(playAllBtn)
}
sectionShowView.addSubview(bulkDeleteBtn)
bulkDeleteBtn.snp.makeConstraints { make in
make.left.equalTo(shuffleBtn.snp.right).offset(18*width)
make.centerY.equalTo(playAllBtn)
}
//
sectionShowView.addSubview(searchBtn)
searchBtn.snp.makeConstraints { make in
@ -395,6 +410,7 @@ class MPPositive_OfflineSongsViewController: MPPositive_BaseViewController {
}
//
@objc private func shuffleClick(_ sender:UIButton) {
view.endEditing(true)
guard offlines.count != 0 else {return}
MPPositive_Debouncer.shared.call {
[weak self] in
@ -435,6 +451,14 @@ class MPPositive_OfflineSongsViewController: MPPositive_BaseViewController {
MP_AnalyticsManager.shared.player_b_listAction()
}
}
//
@objc private func batchDeleteClick(_ sender:UIButton) {
view.endEditing(true)
print("点击了批量删除")
//
let showVC:MPPositive_BatchDeletionViewController = .init(withOfflines: offlines)
navigationController?.pushViewController(showVC, animated: true)
}
}
//MARK: - tableView
extension MPPositive_OfflineSongsViewController: UITableViewDataSource, UITableViewDelegate, UIViewControllerTransitioningDelegate{

View File

@ -258,17 +258,23 @@ class MPPositive_ListShowViewController: MPPositive_BaseViewController, UIViewCo
//
NotificationCenter.notificationKey.post(notificationName: .pup_player_vc)
MP_AnalyticsManager.shared.player_b_impAction()
//next
MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams){ [weak self] listSongs in
guard let self = self else {return}
//playerloadViewModel
let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.browseItem.videoId ?? "")
lodaViewModel.improveData(item.browseItem.videoId ?? "")
//
MP_PlayerManager.shared.setPlayType(.normal)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
MP_AnalyticsManager.shared.player_b_listAction()
var array:[MPPositive_SongItemModel] = []
///
listOrAlbum.items.forEach { browse in
let song = MPPositive_SongItemModel()
song.coverUrls = browse.browseItem.coverUrls
song.reviewUrls = browse.browseItem.coverUrls
song.title = browse.title
song.shortBylineText = browse.subtitle
song.videoId = browse.browseItem.videoId
array.append(song)
}
let lodaViewModel = MPPositive_PlayerLoadViewModel(array, currentVideoId: item.browseItem.videoId ?? "")
lodaViewModel.improveData(item.browseItem.videoId ?? "")
//
MP_PlayerManager.shared.setPlayType(.normal)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
MP_AnalyticsManager.shared.player_b_listAction()
}
}
//
@ -286,17 +292,23 @@ class MPPositive_ListShowViewController: MPPositive_BaseViewController, UIViewCo
//
NotificationCenter.notificationKey.post(notificationName: .pup_player_vc)
MP_AnalyticsManager.shared.player_b_impAction()
//next
MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams){ [weak self] listSongs in
guard let self = self else {return}
//playerloadViewModel
let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.browseItem.videoId ?? "")
lodaViewModel.improveData(item.browseItem.videoId ?? "")
//
MP_PlayerManager.shared.setPlayType(.random)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
MP_AnalyticsManager.shared.player_b_listAction()
var array:[MPPositive_SongItemModel] = []
///
listOrAlbum.items.forEach { browse in
let song = MPPositive_SongItemModel()
song.coverUrls = browse.browseItem.coverUrls
song.reviewUrls = browse.browseItem.coverUrls
song.title = browse.title
song.shortBylineText = browse.subtitle
song.videoId = browse.browseItem.videoId
array.append(song)
}
let lodaViewModel = MPPositive_PlayerLoadViewModel(array, currentVideoId: item.browseItem.videoId ?? "")
lodaViewModel.improveData(item.browseItem.videoId ?? "")
//
MP_PlayerManager.shared.setPlayType(.random)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
MP_AnalyticsManager.shared.player_b_listAction()
}
}
//
@ -400,20 +412,28 @@ extension MPPositive_ListShowViewController: UITableViewDataSource, UITableViewD
return
}
MP_AnalyticsManager.shared.song_clickAction("List")
//
MP_PlayerManager.shared.loadPlayer = nil
//
NotificationCenter.notificationKey.post(notificationName: .pup_player_vc)
MP_AnalyticsManager.shared.player_b_impAction()
//next
MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams){ [weak self] listSongs in
guard let self = self else {return}
//playerloadViewModel
let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: listOrAlbum.items[indexPath.row].browseItem.videoId ?? "")
lodaViewModel.improveData(listOrAlbum.items[indexPath.row].browseItem.videoId ?? "")
//
MP_PlayerManager.shared.setPlayType(.normal)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
MP_AnalyticsManager.shared.player_b_listAction()
var array:[MPPositive_SongItemModel] = []
///
listOrAlbum.items.forEach { browse in
let song = MPPositive_SongItemModel()
song.coverUrls = browse.browseItem.coverUrls
song.reviewUrls = browse.browseItem.coverUrls
song.title = browse.title
song.shortBylineText = browse.subtitle
song.videoId = browse.browseItem.videoId
array.append(song)
}
let lodaViewModel = MPPositive_PlayerLoadViewModel(array, currentVideoId: item.browseItem.videoId ?? "")
lodaViewModel.improveData(item.browseItem.videoId ?? "")
//
MP_PlayerManager.shared.setPlayType(.normal)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
MP_AnalyticsManager.shared.player_b_listAction()
}
}
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {

View File

@ -11,9 +11,15 @@ import Kingfisher
class MPPositive_BottomShowView: UIView {
//绿
private lazy var bgGreenImageView:UIImageView = UIImageView(image: .init(named: "BottomShow'bg"))
//View
private lazy var coverContentView:UIView = {
let view:UIView = .init(frame: .init(x: 26*width, y: 13*width, width: 48*width, height: 48*width))
view.backgroundColor = .clear
return view
}()
//
private lazy var coverImageView:UIImageView = {
let imageView:UIImageView = .init(frame: .init(x: 26*width, y: 13*width, width: 48*width, height: 48*width))
let imageView:UIImageView = .init()
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 24*width
imageView.layer.masksToBounds = true
@ -47,6 +53,8 @@ class MPPositive_BottomShowView: UIView {
btn.addTarget(self, action: #selector(switchStatuClick(_ :)), for: .touchUpInside)
return btn
}()
//
private var isRotating:Bool = false
//
var showListBlock:(() -> Void)?
override init(frame: CGRect) {
@ -73,13 +81,25 @@ class MPPositive_BottomShowView: UIView {
deinit {
NotificationCenter.default.removeObserver(self)
}
override func didMoveToWindow() {
super.didMoveToWindow()
if isRotating {
addRotationAnimation()
}else {
stopRotationAnimation()
}
}
//
private func confirgue() {
addSubview(bgGreenImageView)
bgGreenImageView.snp.makeConstraints { make in
make.left.right.top.bottom.equalToSuperview()
}
addSubview(coverImageView)
addSubview(coverContentView)
coverContentView.addSubview(coverImageView)
coverImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
addSubview(nextBtn)
nextBtn.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-24*width)
@ -129,15 +149,22 @@ class MPPositive_BottomShowView: UIView {
}
//
@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?.playStatuBtn.isSelected = true
default:
self?.playStatuBtn.isSelected = false
guard let state:MP_PlayerStateType = sender.object as? MP_PlayerStateType else {
return
}
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
switch state {
case .Playing:
playStatuBtn.isSelected = true
if isRotating == false {
addRotationAnimation()
}
default:
playStatuBtn.isSelected = false
if isRotating == true {
stopRotationAnimation()
}
}
}
@ -181,4 +208,27 @@ class MPPositive_BottomShowView: UIView {
}
}
}
//Layer
private func addRotationAnimation() {
isRotating = true
DispatchQueue.main.asyncAfter(deadline: .now()) {[weak self] in
guard let self = self, coverImageView.window != nil else {return}
coverContentView.layer.removeAnimation(forKey: "rotationAnimation")
let rotation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.fromValue = 0
rotation.toValue = Double.pi * 2
rotation.duration = 8 //
rotation.repeatCount = Float.infinity //
coverContentView.layer.add(rotation, forKey: "rotationAnimation")
}
}
//Layer
private func stopRotationAnimation() {
isRotating = false //
DispatchQueue.main.asyncAfter(deadline: .now()) {[weak self] in
guard let self = self else {return}
coverContentView.layer.removeAnimation(forKey: "rotationAnimation")
coverContentView.layer.transform = CATransform3DIdentity
}
}
}

View File

@ -0,0 +1,34 @@
//
// MPPositive_DefaultTableView.swift
// relax.offline.mp3.music
//
// Created by Mr.Zhou on 2024/12/24.
//
import UIKit
///tableView
class MPPositive_DefaultTableView: UITableView {
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
//
private func configure() {
self.backgroundColor = .clear
self.showsVerticalScrollIndicator = false
self.showsHorizontalScrollIndicator = false
self.separatorStyle = .none
self.estimatedRowHeight = 200
self.rowHeight = UITableView.automaticDimension
self.contentInset = .init(top: 0, left: 0, bottom: 70*width, right: 0)
if #available(iOS 15.0, *) {
self.sectionHeaderTopPadding = 0
}
}
}

View File

@ -51,6 +51,23 @@ class MPPositive_AddSongTableViewCell: UITableViewCell {
}
}
}
var download:MPPositive_DownloadViewModel!{
didSet{
download.setImage(iconImageView)
titleLabel.text = download.title
subtitleLabel.text = download.subtitle
}
}
var statu:Bool!{
didSet{
if statu == false {
statuImageView.image = UIImage(named: "UnAdd_PlayLists'logo")
}else {
statuImageView.image = UIImage(named: "Added_PlayList'logo")
}
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none