B面1.1.5内购提审版

This commit is contained in:
Mr.zhou 2024-08-02 18:18:18 +08:00
parent 732d471df7
commit 7b17174467
57 changed files with 2032 additions and 210 deletions

View File

@ -23,6 +23,10 @@
CB1E3B662C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1E3B652C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift */; };
CB1E3B682C23E09100071DEA /* MPPositive_CustomVideoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1E3B672C23E09100071DEA /* MPPositive_CustomVideoModel.swift */; };
CB20A0702C53BDBF00FC5AFC /* MP_WebVisitorDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB20A06F2C53BDBF00FC5AFC /* MP_WebVisitorDataManager.swift */; };
CB2CAAD42C59DC1100EF691D /* MPPositive_TrashListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2CAAD32C59DC1100EF691D /* MPPositive_TrashListModel.swift */; };
CB2CAAD72C5A1AC500EF691D /* MP_IAPViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CB2CAAD62C5A1AC500EF691D /* MP_IAPViewController.xib */; };
CB2CAAD82C5A1AC500EF691D /* MP_IAPViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2CAAD52C5A1AC500EF691D /* MP_IAPViewController.swift */; };
CB4FA4D92C5CDC4A0027C949 /* relax.offline.mp3.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CB4FA4D72C5CDC4A0027C949 /* relax.offline.mp3.xcdatamodeld */; };
CB7FC5422C2AA01F00292A43 /* FacebookAEM in Frameworks */ = {isa = PBXBuildFile; productRef = CB7FC5412C2AA01F00292A43 /* FacebookAEM */; };
CB7FC5442C2AA01F00292A43 /* FacebookBasics in Frameworks */ = {isa = PBXBuildFile; productRef = CB7FC5432C2AA01F00292A43 /* FacebookBasics */; };
CB7FC5462C2AA01F00292A43 /* FacebookCore in Frameworks */ = {isa = PBXBuildFile; productRef = CB7FC5452C2AA01F00292A43 /* FacebookCore */; };
@ -238,7 +242,6 @@
CBC2D6F82BFDF3D800E17703 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CBC2D6F72BFDF3D800E17703 /* Assets.xcassets */; };
CBC2D6FB2BFDF3D800E17703 /* Base in Resources */ = {isa = PBXBuildFile; fileRef = CBC2D6FA2BFDF3D800E17703 /* Base */; };
CBC2D7D42BFDF4B900E17703 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = CBC2D7792BFDF4B900E17703 /* PrivacyInfo.xcprivacy */; };
CBC2EBCA2C5277F1000ADA51 /* relax.offline.mp3.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CBC2EBC82C5277F1000ADA51 /* relax.offline.mp3.xcdatamodeld */; };
CBC3F2B22C3E76160075DC74 /* MPPositive_AdModelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC3F2B12C3E76160075DC74 /* MPPositive_AdModelModel.swift */; };
CBC81FBA2C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC81FB92C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift */; };
CBC81FBC2C3696230028143B /* MPPositive_HomeSingleCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC81FBB2C3696230028143B /* MPPositive_HomeSingleCollectionViewCell.swift */; };
@ -274,6 +277,10 @@
CB1E3B652C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CustomPlayListModel.swift; sourceTree = "<group>"; };
CB1E3B672C23E09100071DEA /* MPPositive_CustomVideoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CustomVideoModel.swift; sourceTree = "<group>"; };
CB20A06F2C53BDBF00FC5AFC /* MP_WebVisitorDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_WebVisitorDataManager.swift; sourceTree = "<group>"; };
CB2CAAD32C59DC1100EF691D /* MPPositive_TrashListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_TrashListModel.swift; sourceTree = "<group>"; };
CB2CAAD52C5A1AC500EF691D /* MP_IAPViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_IAPViewController.swift; sourceTree = "<group>"; };
CB2CAAD62C5A1AC500EF691D /* MP_IAPViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MP_IAPViewController.xib; sourceTree = "<group>"; };
CB4FA4D82C5CDC4A0027C949 /* MusicPlayer.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MusicPlayer.xcdatamodel; sourceTree = "<group>"; };
CB7FC5472C2AC25C00292A43 /* MPPositive_CenterListSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CenterListSearchView.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>"; };
@ -485,7 +492,6 @@
CBC2D6FA2BFDF3D800E17703 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
CBC2D6FC2BFDF3D800E17703 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
CBC2D7792BFDF4B900E17703 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
CBC2EBC92C5277F1000ADA51 /* MusicPlayer.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MusicPlayer.xcdatamodel; sourceTree = "<group>"; };
CBC3F2B12C3E76160075DC74 /* MPPositive_AdModelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_AdModelModel.swift; sourceTree = "<group>"; };
CBC81FB92C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_HomeSinglesTableViewCell.swift; sourceTree = "<group>"; };
CBC81FBB2C3696230028143B /* MPPositive_HomeSingleCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_HomeSingleCollectionViewCell.swift; sourceTree = "<group>"; };
@ -562,6 +568,8 @@
CBAFC9F42C0A10500054500E /* MP_LunchViewController.xib */,
CB15B8992C353B2400756E89 /* MP_GuideViewController.swift */,
CB15B89A2C353B2400756E89 /* MP_GuideViewController.xib */,
CB2CAAD52C5A1AC500EF691D /* MP_IAPViewController.swift */,
CB2CAAD62C5A1AC500EF691D /* MP_IAPViewController.xib */,
);
path = Controllers;
sourceTree = "<group>";
@ -586,7 +594,7 @@
CBAFC9FB2C0A10500054500E /* DataBase */ = {
isa = PBXGroup;
children = (
CBC2EBC82C5277F1000ADA51 /* relax.offline.mp3.xcdatamodeld */,
CB4FA4D72C5CDC4A0027C949 /* relax.offline.mp3.xcdatamodeld */,
);
path = DataBase;
sourceTree = "<group>";
@ -750,6 +758,7 @@
CBAFCA462C0A10500054500E /* MPPositive_SongItemModel.swift */,
CB1E3B652C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift */,
CB1E3B672C23E09100071DEA /* MPPositive_CustomVideoModel.swift */,
CB2CAAD32C59DC1100EF691D /* MPPositive_TrashListModel.swift */,
);
path = Models;
sourceTree = "<group>";
@ -1306,6 +1315,7 @@
CBAFCB022C0A10500054500E /* Howling Wind.mp3 in Resources */,
CBAFCB842C0A10500054500E /* MPSideA_DeleteViewController.xib in Resources */,
CBAFCB822C0A10500054500E /* MPSideA_CenterViewController.xib in Resources */,
CB2CAAD72C5A1AC500EF691D /* MP_IAPViewController.xib in Resources */,
CBAFCB062C0A10500054500E /* waterfall.mp3 in Resources */,
CBAFCAFE2C0A10500054500E /* Beach.mp3 in Resources */,
CBC2D7D42BFDF4B900E17703 /* PrivacyInfo.xcprivacy in Resources */,
@ -1412,6 +1422,7 @@
CBC81FBA2C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift in Sources */,
CBAFCB252C0A10500054500E /* MPPositive_CollectionArtistModel.swift in Sources */,
CBAFCB702C0A10500054500E /* MPPositive_SearchResultShowTableViewCell.swift in Sources */,
CB2CAAD42C59DC1100EF691D /* MPPositive_TrashListModel.swift in Sources */,
CBAFCB662C0A10500054500E /* MPPositive_HomeShowTableViewCell.swift in Sources */,
CBAFCB352C0A10500054500E /* MPPositive_ListAlbumListViewModel.swift in Sources */,
CBB75FDD2C4F7AA60041665D /* UIImageView.swift in Sources */,
@ -1424,10 +1435,12 @@
CBAFCAF52C0A10500054500E /* CoreDataDelegete.swift in Sources */,
CBAFCB5B2C0A10500054500E /* MPPositive_ArtistShowCollectionViewCell.swift in Sources */,
CBAFCB182C0A10500054500E /* MPPositive_JsonArtistMore.swift in Sources */,
CB4FA4D92C5CDC4A0027C949 /* relax.offline.mp3.xcdatamodeld in Sources */,
CBAFCB982C0A10500054500E /* MPSideA_CustomTabBarItem.swift in Sources */,
CBAFCB5D2C0A10500054500E /* MPPositive_ArtistShowListableViewCell.swift in Sources */,
CBAFCB7D2C0A10500054500E /* MPSideA_PresentationController.swift in Sources */,
CBAFCB2D2C0A10500054500E /* MPPositive_ArtistContentListViewModel.swift in Sources */,
CB2CAAD82C5A1AC500EF691D /* MP_IAPViewController.swift in Sources */,
CBC1FB7E2C509BB400AC0633 /* MPPositive_LibraryListViewModel.swift in Sources */,
CBAFCB992C0A10500054500E /* MPSideA_CustomTabBarView.swift in Sources */,
CBAFCB342C0A10500054500E /* MPPositive_DownloadViewModel.swift in Sources */,
@ -1446,7 +1459,6 @@
CBAFCB7B2C0A10500054500E /* MPSideA_BaseViewController.swift in Sources */,
CBAFCB102C0A10500054500E /* MP_NetWorkManager.swift in Sources */,
CBAFCB9D2C0A10500054500E /* MPSideA_SettingTableViewCell.swift in Sources */,
CBC2EBCA2C5277F1000ADA51 /* relax.offline.mp3.xcdatamodeld in Sources */,
CBAFCAEC2C0A10500054500E /* AVPlayerItem.swift in Sources */,
CBAFCB7E2C0A10500054500E /* MPSideA_TabBarController.swift in Sources */,
CBAFCB1D2C0A10500054500E /* MPPositive_JsonPlayer.swift in Sources */,
@ -1730,10 +1742,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1.1.4.1;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1.1.5.1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = T93S37G27F;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = RAQJ4FNZUH;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = relax.offline.mp3.music/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Musiclax;
@ -1751,10 +1765,11 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.4;
MARKETING_VERSION = 1.1.5;
PRODUCT_BUNDLE_IDENTIFIER = relax.offline.mp3.music;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Musiclax_Development;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@ -1773,10 +1788,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1.1.4.1;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1.1.5.1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = T93S37G27F;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = RAQJ4FNZUH;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = relax.offline.mp3.music/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Musiclax;
@ -1794,10 +1811,11 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.1.4;
MARKETING_VERSION = 1.1.5;
PRODUCT_BUNDLE_IDENTIFIER = relax.offline.mp3.music;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Musiclax_Development;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@ -1898,12 +1916,12 @@
/* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */
CBC2EBC82C5277F1000ADA51 /* relax.offline.mp3.xcdatamodeld */ = {
CB4FA4D72C5CDC4A0027C949 /* relax.offline.mp3.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
CBC2EBC92C5277F1000ADA51 /* MusicPlayer.xcdatamodel */,
CB4FA4D82C5CDC4A0027C949 /* MusicPlayer.xcdatamodel */,
);
currentVersion = CBC2EBC92C5277F1000ADA51 /* MusicPlayer.xcdatamodel */;
currentVersion = CB4FA4D82C5CDC4A0027C949 /* MusicPlayer.xcdatamodel */;
name = relax.offline.mp3.xcdatamodeld;
path = "/Users/zhou/Desktop/纳克斯互娱/relax.offline.mp3.music/relax.offline.mp3.music/MP/Common/DataBase/relax.offline.mp3.xcdatamodeld";
sourceTree = "<group>";

View File

@ -13,6 +13,7 @@ import Tiercel
import Firebase
import GoogleMobileAds
import FacebookCore
import StoreKit
@_exported import IQKeyboardManagerSwift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@ -61,7 +62,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
switch_lunch()
//
MP_AnalyticsManager.shared.user_launchAction()
// NotificationCenter.default.addObserver(self, selector: #selector(appWillTerminateAction(_ :)), name:UIApplication.willTerminateNotification, object: nil)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:] ) -> Bool {

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,177 @@
//
// MP_IAPViewController.swift
// relax.offline.mp3.music
//
// Created by Mr.Zhou on 2024/7/31.
//
import UIKit
///
let IAPChooseedImage:UIImage? = .init(named: "IAP Chooseed'logo")
///
let IAPChooseImage:UIImage? = .init(named: "IAP Choose'logo")
///A/B
class MP_IAPViewController: UIViewController {
//A/B
@IBOutlet weak var bgImageView: UIImageView!
@IBOutlet weak var scrollView: UIScrollView!
var isType:Bool = false
@IBOutlet weak var aConstraint: NSLayoutConstraint!
@IBOutlet weak var bConstraint: NSLayoutConstraint!
@IBOutlet weak var adView: UIView!
@IBOutlet weak var adLabel: UILabel!
@IBOutlet weak var musicView: UIView!
@IBOutlet weak var musicLabel: UILabel!
@IBOutlet weak var downloadView: UIView!
@IBOutlet weak var downloadLabel: UILabel!
@IBOutlet weak var weekView: UIView!{
didSet{
weekView.isUserInteractionEnabled = true
weekView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(chooseLevelClick(_ :))))
}
}
@IBOutlet weak var weekImageView: UIImageView!
@IBOutlet weak var weekPriceLabel: UILabel!
@IBOutlet weak var yearView: UIView!{
didSet{
yearView.isUserInteractionEnabled = true
yearView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(chooseLevelClick(_ :))))
}
}
@IBOutlet weak var yearImageView: UIImageView!
@IBOutlet weak var yearPriceLabel: UILabel!
@IBOutlet weak var lifeView: UIView!{
didSet{
lifeView.isUserInteractionEnabled = true
lifeView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(chooseLevelClick(_ :))))
}
}
@IBOutlet weak var lifeImageView: UIImageView!
@IBOutlet weak var lifePriceLabel: UILabel!
var privacyBlock:(() -> Void)?
var termsBlock:(() -> Void)?
//
private var level:Int?
override func viewDidLoad() {
super.viewDidLoad()
scrollView.contentInsetAdjustmentBehavior = .never
MP_IAPManager.shared.requestProducts()
//isTypeA/B
if isType {
//B
bgImageView.image = UIImage(named: "IAP B'bg")
aConstraint.priority = .init(500)
bConstraint.priority = .init(999)
//
musicView.isHidden = false
downloadView.isHidden = false
}else {
//A
bgImageView.image = UIImage(named: "IAP A'bg")
aConstraint.priority = .init(999)
bConstraint.priority = .init(500)
//
musicView.isHidden = true
downloadView.isHidden = true
}
//
adLabel.attributedText = setSubstring("Ad-free experience, NO ADs!!", coloredText: "NO ADs!!")
musicLabel.text = "All \"YouTube\" music & videos"
downloadLabel.text = "Unlimited Downloads"
//
weekPriceLabel.attributedText = setPriceText(1.99)
yearPriceLabel.attributedText = setPriceText(14.99)
lifePriceLabel.attributedText = setPriceText(24.99)
}
//
private func setSubstring(_ fullText:String, coloredText:String) -> NSAttributedString {
//
let attributedString = NSMutableAttributedString(string: fullText, attributes: [.foregroundColor:UIColor.white, .font:UIFont.systemFont(ofSize: 16*width)])
let attributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor(hex: "#80F988")]
if let range = fullText.range(of: coloredText) {
let nsRange = NSRange(range, in: fullText)
attributedString.addAttributes(attributes, range: nsRange)
}
return attributedString
}
//
private func setPriceText(_ price:Double) -> NSAttributedString {
let font = UIFont(name: "DINAlternate-Bold", size: 24*width) ?? .systemFont(ofSize: 24*width, weight: .bold)
let attributedString = NSMutableAttributedString(string: "$\(price)", attributes: [.foregroundColor:UIColor.white, .font:font])
attributedString.addAttributes([.font:UIFont(name: "DINAlternate-Bold", size: 16*width) ?? .systemFont(ofSize: 16*width, weight: .bold)], range: .init(location: 0, length: 1))
return attributedString
}
//退
@IBAction func dismissClick(_ sender: UIButton) {
dismiss(animated: true)
}
//
@objc private func chooseLevelClick(_ sender:UITapGestureRecognizer) {
let tag = sender.view?.tag ?? 0
switch tag {
case 0://
weekPriceLabel.setGradientTextColor(gradientTextColors)
weekImageView.image = IAPChooseedImage
yearPriceLabel.cleanGradientTextColor()
yearImageView.image = IAPChooseImage
lifePriceLabel.cleanGradientTextColor()
lifeImageView.image = IAPChooseImage
case 1://
yearPriceLabel.setGradientTextColor(gradientTextColors)
yearImageView.image = IAPChooseedImage
weekPriceLabel.cleanGradientTextColor()
weekImageView.image = IAPChooseImage
lifePriceLabel.cleanGradientTextColor()
lifeImageView.image = IAPChooseImage
default://
lifePriceLabel.setGradientTextColor(gradientTextColors)
lifeImageView.image = IAPChooseedImage
weekPriceLabel.cleanGradientTextColor()
weekImageView.image = IAPChooseImage
yearPriceLabel.cleanGradientTextColor()
yearImageView.image = IAPChooseImage
}
level = tag
}
//
@IBAction func continueClick(_ sender: UIButton) {
guard let level = level else {
MP_HUD.onlytext("Please select your membership type", delay: 1.0, completion: nil)
return
}
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
MP_HUD.onlytext("Bad connection~", delay: 1.0, completion: nil)
return
}
MP_IAPManager.shared.purchaseProduct(level)
}
//
@IBAction func reStoreClick(_ sender: UIButton) {
MP_IAPManager.shared.restorePurchases()
}
//
@IBAction func privacyClick(_ sender: UIButton) {
dismiss(animated: true) {
[weak self] in
if let block = self?.privacyBlock {
block()
}
}
}
//
@IBAction func termsClick(_ sender: UIButton) {
dismiss(animated: true) {
[weak self] in
if let block = self?.termsBlock {
block()
}
}
}
}

View File

@ -0,0 +1,611 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MP_IAPViewController" customModule="relax_offline_mp3_music" customModuleProvider="target">
<connections>
<outlet property="aConstraint" destination="tVb-7S-rd8" id="VvO-cU-hrO"/>
<outlet property="adLabel" destination="yNx-kt-wCp" id="QqE-FX-NJo"/>
<outlet property="adView" destination="5rd-jg-Oh0" id="gCW-Ff-moN"/>
<outlet property="bConstraint" destination="WeJ-cY-e6e" id="upI-wE-tCe"/>
<outlet property="bgImageView" destination="kdc-al-Dgu" id="6CO-xr-HXk"/>
<outlet property="downloadLabel" destination="yho-5R-DjF" id="e2d-Gj-P52"/>
<outlet property="downloadView" destination="s0J-Ld-XhO" id="4Qr-Gx-apD"/>
<outlet property="lifeImageView" destination="21u-ne-klE" id="WRc-K8-9x9"/>
<outlet property="lifePriceLabel" destination="mSD-Ht-ZAt" id="E4r-BI-tvl"/>
<outlet property="lifeView" destination="6m2-Pk-kEx" id="qGY-HI-O0p"/>
<outlet property="musicLabel" destination="bmg-bY-SQ2" id="asP-Of-UO6"/>
<outlet property="musicView" destination="4aH-sS-rjT" id="Oq2-nH-VSO"/>
<outlet property="scrollView" destination="BnJ-Xo-PqP" id="aAq-Mw-9Bt"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
<outlet property="weekImageView" destination="f2Z-iY-0aL" id="1Me-2I-A4f"/>
<outlet property="weekPriceLabel" destination="zj9-cg-9xc" id="tPL-3l-Cuj"/>
<outlet property="weekView" destination="fVE-zT-baW" id="sLb-h7-9QP"/>
<outlet property="yearImageView" destination="Y9f-zt-bGB" id="cuk-g0-HuP"/>
<outlet property="yearPriceLabel" destination="C3t-AB-geN" id="VHn-eq-H4N"/>
<outlet property="yearView" destination="cw2-8u-Yru" id="2OH-Gs-zPb"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BnJ-Xo-PqP">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nGh-s6-UA5">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP B'bg" translatesAutoresizingMaskIntoConstraints="NO" id="kdc-al-Dgu">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<constraints>
<constraint firstAttribute="height" constant="812" id="ZvV-J5-NWh">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Rights'logo" translatesAutoresizingMaskIntoConstraints="NO" id="JBI-cg-ZTm">
<rect key="frame" x="3.5" y="66" width="229" height="149"/>
<constraints>
<constraint firstAttribute="height" constant="149" id="CKo-WY-ajE">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="width" constant="229" id="P6i-Im-9dq">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5rd-jg-Oh0">
<rect key="frame" x="19" y="204" width="337" height="25"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP AD'logo" translatesAutoresizingMaskIntoConstraints="NO" id="1uD-GG-xPH">
<rect key="frame" x="13" y="0.5" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="1uT-Ez-xQz">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="height" constant="24" id="OGY-K2-quX">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yNx-kt-wCp">
<rect key="frame" x="45" y="2.5" width="292" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="yNx-kt-wCp" secondAttribute="trailing" id="1s1-5F-p0S"/>
<constraint firstAttribute="height" constant="25" id="AV7-GY-Eog">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="yNx-kt-wCp" firstAttribute="centerY" secondItem="5rd-jg-Oh0" secondAttribute="centerY" id="DC6-iU-ltm"/>
<constraint firstItem="1uD-GG-xPH" firstAttribute="leading" secondItem="5rd-jg-Oh0" secondAttribute="leading" constant="13" id="MEB-ro-ftA">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="1uD-GG-xPH" firstAttribute="centerY" secondItem="5rd-jg-Oh0" secondAttribute="centerY" id="VPN-ZV-bJN"/>
<constraint firstItem="yNx-kt-wCp" firstAttribute="leading" secondItem="1uD-GG-xPH" secondAttribute="trailing" constant="8" id="WnA-fm-3Sr">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4aH-sS-rjT">
<rect key="frame" x="19" y="240" width="337" height="25"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP Mu'logo" translatesAutoresizingMaskIntoConstraints="NO" id="TIT-KH-pqz">
<rect key="frame" x="13" y="0.5" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="FDT-ue-3VW">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="height" constant="24" id="YtB-hc-LKm">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bmg-bY-SQ2">
<rect key="frame" x="45" y="2.5" width="292" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="TIT-KH-pqz" firstAttribute="centerY" secondItem="4aH-sS-rjT" secondAttribute="centerY" id="Jma-0o-3jg"/>
<constraint firstItem="bmg-bY-SQ2" firstAttribute="leading" secondItem="TIT-KH-pqz" secondAttribute="trailing" constant="8" id="NsQ-iG-rer">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="height" constant="25" id="WL4-4H-OhN">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="bmg-bY-SQ2" firstAttribute="centerY" secondItem="4aH-sS-rjT" secondAttribute="centerY" id="ZLr-OR-FES"/>
<constraint firstItem="TIT-KH-pqz" firstAttribute="leading" secondItem="4aH-sS-rjT" secondAttribute="leading" constant="13" id="ldO-8g-BiT">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="trailing" secondItem="bmg-bY-SQ2" secondAttribute="trailing" id="zhU-hn-ZNb"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s0J-Ld-XhO">
<rect key="frame" x="19" y="276" width="337" height="25"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP Dn'logo" translatesAutoresizingMaskIntoConstraints="NO" id="EW0-Rs-5el">
<rect key="frame" x="13" y="0.5" width="24" height="24"/>
<constraints>
<constraint firstAttribute="height" constant="24" id="5Z9-J6-VbC">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="width" constant="24" id="AA0-mY-m5l">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yho-5R-DjF">
<rect key="frame" x="45" y="2.5" width="292" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="EW0-Rs-5el" firstAttribute="leading" secondItem="s0J-Ld-XhO" secondAttribute="leading" constant="13" id="6d1-42-qVf">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="yho-5R-DjF" firstAttribute="leading" secondItem="EW0-Rs-5el" secondAttribute="trailing" constant="8" id="FYP-T2-zeV">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="yho-5R-DjF" firstAttribute="centerY" secondItem="s0J-Ld-XhO" secondAttribute="centerY" id="KDE-um-4t7"/>
<constraint firstItem="EW0-Rs-5el" firstAttribute="centerY" secondItem="s0J-Ld-XhO" secondAttribute="centerY" id="jXb-jB-AaL"/>
<constraint firstAttribute="height" constant="25" id="k3a-ku-dAt">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="trailing" secondItem="yho-5R-DjF" secondAttribute="trailing" id="xQK-xD-NxY"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fVE-zT-baW">
<rect key="frame" x="19" y="364" width="337" height="69"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP Choose'logo" translatesAutoresizingMaskIntoConstraints="NO" id="f2Z-iY-0aL">
<rect key="frame" x="0.0" y="0.0" width="337" height="69"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zj9-cg-9xc">
<rect key="frame" x="19" y="20.5" width="56" height="28"/>
<fontDescription key="fontDescription" name="DINAlternate-Bold" family="DIN Alternate" pointSize="24"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="/ Week" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sOg-Lz-yAo">
<rect key="frame" x="79" y="27.5" width="52" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="f2Z-iY-0aL" secondAttribute="trailing" id="4wT-u1-Enh"/>
<constraint firstItem="f2Z-iY-0aL" firstAttribute="top" secondItem="fVE-zT-baW" secondAttribute="top" id="Hc6-PF-3DH"/>
<constraint firstItem="f2Z-iY-0aL" firstAttribute="leading" secondItem="fVE-zT-baW" secondAttribute="leading" id="Kpb-Os-axJ"/>
<constraint firstItem="zj9-cg-9xc" firstAttribute="centerY" secondItem="fVE-zT-baW" secondAttribute="centerY" id="Pct-qk-N9a"/>
<constraint firstAttribute="height" constant="69" id="RvF-7J-de6">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="bottom" secondItem="f2Z-iY-0aL" secondAttribute="bottom" id="Scv-pU-07I"/>
<constraint firstAttribute="width" constant="337" id="T1e-l0-fNS">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="zj9-cg-9xc" firstAttribute="leading" secondItem="fVE-zT-baW" secondAttribute="leading" constant="19" id="VSA-vD-pcL">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="sOg-Lz-yAo" firstAttribute="bottom" secondItem="zj9-cg-9xc" secondAttribute="bottom" id="h7K-PI-r0Z"/>
<constraint firstItem="sOg-Lz-yAo" firstAttribute="leading" secondItem="zj9-cg-9xc" secondAttribute="trailing" constant="4" id="nEh-6r-TBY"/>
</constraints>
</view>
<view tag="1" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cw2-8u-Yru">
<rect key="frame" x="19" y="457" width="337" height="69"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP Choose'logo" translatesAutoresizingMaskIntoConstraints="NO" id="Y9f-zt-bGB">
<rect key="frame" x="0.0" y="0.0" width="337" height="69"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C3t-AB-geN">
<rect key="frame" x="19" y="20.5" width="56" height="28"/>
<fontDescription key="fontDescription" name="DINAlternate-Bold" family="DIN Alternate" pointSize="24"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="/ Year" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ONJ-Ib-N5a">
<rect key="frame" x="79" y="27.5" width="43" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="C3t-AB-geN" firstAttribute="leading" secondItem="cw2-8u-Yru" secondAttribute="leading" constant="19" id="4Eq-cN-JNK">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="ONJ-Ib-N5a" firstAttribute="bottom" secondItem="C3t-AB-geN" secondAttribute="bottom" id="AH1-HF-g6k"/>
<constraint firstAttribute="trailing" secondItem="Y9f-zt-bGB" secondAttribute="trailing" id="ASd-yV-Kd7"/>
<constraint firstAttribute="bottom" secondItem="Y9f-zt-bGB" secondAttribute="bottom" id="BPY-Tq-XZx"/>
<constraint firstAttribute="width" constant="337" id="JA4-8u-G6U">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="ONJ-Ib-N5a" firstAttribute="leading" secondItem="C3t-AB-geN" secondAttribute="trailing" constant="4" id="TwV-2i-A47"/>
<constraint firstAttribute="height" constant="69" id="UHf-8S-8nj">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="Y9f-zt-bGB" firstAttribute="top" secondItem="cw2-8u-Yru" secondAttribute="top" id="bK4-7v-Q0s"/>
<constraint firstItem="C3t-AB-geN" firstAttribute="centerY" secondItem="cw2-8u-Yru" secondAttribute="centerY" id="lVU-qb-XvJ"/>
<constraint firstItem="Y9f-zt-bGB" firstAttribute="leading" secondItem="cw2-8u-Yru" secondAttribute="leading" id="mNj-wW-BXl"/>
</constraints>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP Save'bg" translatesAutoresizingMaskIntoConstraints="NO" id="usZ-hA-14r">
<rect key="frame" x="249.5" y="443" width="87" height="27"/>
<constraints>
<constraint firstAttribute="height" constant="27" id="9Xc-Vw-fSW">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="width" constant="87" id="wjD-g1-aYG">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Save 85%" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qu9-bX-6KG">
<rect key="frame" x="263.5" y="449" width="59" height="15"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<view tag="2" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6m2-Pk-kEx">
<rect key="frame" x="19" y="550" width="337" height="69"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IAP Choose'logo" translatesAutoresizingMaskIntoConstraints="NO" id="21u-ne-klE">
<rect key="frame" x="0.0" y="0.0" width="337" height="69"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mSD-Ht-ZAt">
<rect key="frame" x="19" y="20.5" width="56" height="28"/>
<fontDescription key="fontDescription" name="DINAlternate-Bold" family="DIN Alternate" pointSize="24"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="/ Lifetime" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="X28-0N-0hT">
<rect key="frame" x="79" y="27.5" width="70" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="69" id="Ers-Zw-6gy">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="X28-0N-0hT" firstAttribute="bottom" secondItem="mSD-Ht-ZAt" secondAttribute="bottom" id="MoV-Jc-Mn4"/>
<constraint firstItem="21u-ne-klE" firstAttribute="top" secondItem="6m2-Pk-kEx" secondAttribute="top" id="U0t-Xy-FqS"/>
<constraint firstItem="X28-0N-0hT" firstAttribute="leading" secondItem="mSD-Ht-ZAt" secondAttribute="trailing" constant="4" id="XTz-2I-8ny"/>
<constraint firstAttribute="width" constant="337" id="dM3-pv-Ig8">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="mSD-Ht-ZAt" firstAttribute="centerY" secondItem="6m2-Pk-kEx" secondAttribute="centerY" id="ej2-LQ-sAP"/>
<constraint firstItem="21u-ne-klE" firstAttribute="leading" secondItem="6m2-Pk-kEx" secondAttribute="leading" id="gbt-bf-0hn"/>
<constraint firstAttribute="trailing" secondItem="21u-ne-klE" secondAttribute="trailing" id="opl-fF-WbS"/>
<constraint firstAttribute="bottom" secondItem="21u-ne-klE" secondAttribute="bottom" id="tYv-J5-cDq"/>
<constraint firstItem="mSD-Ht-ZAt" firstAttribute="leading" secondItem="6m2-Pk-kEx" secondAttribute="leading" constant="19" id="vYE-qY-r8q">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No mandatory,cancel at anytime" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m4k-if-t1p">
<rect key="frame" x="103" y="657" width="195" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0ZS-PD-jbN">
<rect key="frame" x="20" y="693" width="335" height="52"/>
<color key="backgroundColor" red="0.50196078431372548" green="0.97647058823529409" blue="0.53333333333333333" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="52" id="LoK-kz-miC">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="width" constant="335" id="O2F-0w-Twf">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Continue">
<color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="14"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="continueClick:" destination="-1" eventType="touchUpInside" id="I6j-Wp-jld"/>
</connections>
</button>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="No mandatory'logo" translatesAutoresizingMaskIntoConstraints="NO" id="GJR-RQ-rZY">
<rect key="frame" x="81" y="657" width="16" height="16"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="IrK-vo-oLG">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="width" constant="16" id="Ygb-nL-Bp6">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ot4-pt-BUj">
<rect key="frame" x="164" y="763" width="47" height="28"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Restore">
<color key="titleColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="reStoreClick:" destination="-1" eventType="touchUpInside" id="R4J-W4-aXF"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6ck-rH-HPa">
<rect key="frame" x="20" y="763" width="81" height="28"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Terms of Use">
<color key="titleColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="termsClick:" destination="-1" eventType="touchUpInside" id="gJc-0d-5Wb"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GrN-6O-QqU">
<rect key="frame" x="271" y="763" width="84" height="28"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Privacy Policy">
<color key="titleColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="privacyClick:" destination="-1" eventType="touchUpInside" id="6kq-5c-OnT"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="0ZS-PD-jbN" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="0iZ-ba-oFV"/>
<constraint firstItem="m4k-if-t1p" firstAttribute="leading" secondItem="GJR-RQ-rZY" secondAttribute="trailing" constant="6" id="2BZ-6H-rWz">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="Ot4-pt-BUj" firstAttribute="top" secondItem="0ZS-PD-jbN" secondAttribute="bottom" constant="18" id="2RC-z3-9bc">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="Ot4-pt-BUj" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="2Rd-mO-aZJ"/>
<constraint firstItem="0ZS-PD-jbN" firstAttribute="top" secondItem="m4k-if-t1p" secondAttribute="bottom" constant="20" id="2v7-g2-sam">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="cw2-8u-Yru" firstAttribute="top" secondItem="fVE-zT-baW" secondAttribute="bottom" constant="24" id="6ig-Mk-Ozp">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="5rd-jg-Oh0" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="977-jE-taE"/>
<constraint firstItem="4aH-sS-rjT" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="AX8-Pm-KiJ"/>
<constraint firstItem="JBI-cg-ZTm" firstAttribute="top" secondItem="nGh-s6-UA5" secondAttribute="top" constant="66" id="AdY-Pj-ibu">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="4aH-sS-rjT" firstAttribute="top" secondItem="5rd-jg-Oh0" secondAttribute="bottom" constant="11" id="Ci4-6G-tIg">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="usZ-hA-14r" firstAttribute="trailing" secondItem="cw2-8u-Yru" secondAttribute="trailing" constant="-19.5" id="F73-qC-gcw">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="cw2-8u-Yru" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="FpI-g3-B2C"/>
<constraint firstAttribute="trailing" secondItem="kdc-al-Dgu" secondAttribute="trailing" id="G1M-BI-TxB"/>
<constraint firstItem="6ck-rH-HPa" firstAttribute="leading" secondItem="0ZS-PD-jbN" secondAttribute="leading" id="L1f-uf-qI2"/>
<constraint firstItem="m4k-if-t1p" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" multiplier="1.07" id="L8B-66-nB3"/>
<constraint firstItem="qu9-bX-6KG" firstAttribute="centerY" secondItem="usZ-hA-14r" secondAttribute="centerY" id="Lbn-XX-Xna"/>
<constraint firstItem="s0J-Ld-XhO" firstAttribute="top" secondItem="4aH-sS-rjT" secondAttribute="bottom" constant="11" id="OeH-wx-DYL">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="qu9-bX-6KG" firstAttribute="centerX" secondItem="usZ-hA-14r" secondAttribute="centerX" id="PlX-PY-CFh"/>
<constraint firstItem="kdc-al-Dgu" firstAttribute="leading" secondItem="nGh-s6-UA5" secondAttribute="leading" id="RfD-ny-np9"/>
<constraint firstItem="6m2-Pk-kEx" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="ShO-bi-I02"/>
<constraint firstItem="5rd-jg-Oh0" firstAttribute="top" secondItem="JBI-cg-ZTm" secondAttribute="bottom" constant="-11" id="TqH-pX-5SQ">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="s0J-Ld-XhO" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="WCD-Jc-WSm"/>
<constraint firstItem="fVE-zT-baW" firstAttribute="top" secondItem="s0J-Ld-XhO" secondAttribute="bottom" priority="999" constant="63" id="WeJ-cY-e6e">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="4aH-sS-rjT" firstAttribute="width" secondItem="5rd-jg-Oh0" secondAttribute="width" id="bZi-ts-0lb"/>
<constraint firstItem="s0J-Ld-XhO" firstAttribute="width" secondItem="4aH-sS-rjT" secondAttribute="width" id="dkz-iw-mR6"/>
<constraint firstItem="GrN-6O-QqU" firstAttribute="centerY" secondItem="Ot4-pt-BUj" secondAttribute="centerY" id="fWe-BZ-WpW"/>
<constraint firstItem="JBI-cg-ZTm" firstAttribute="leading" secondItem="nGh-s6-UA5" secondAttribute="leading" constant="3.3999999999999999" id="lHh-M8-ZWB">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="GrN-6O-QqU" firstAttribute="trailing" secondItem="0ZS-PD-jbN" secondAttribute="trailing" id="pAf-0M-8a8"/>
<constraint firstItem="6m2-Pk-kEx" firstAttribute="top" secondItem="cw2-8u-Yru" secondAttribute="bottom" constant="24" id="qru-Oo-f1x">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="GJR-RQ-rZY" firstAttribute="centerY" secondItem="m4k-if-t1p" secondAttribute="centerY" id="siD-on-ehc"/>
<constraint firstItem="fVE-zT-baW" firstAttribute="top" secondItem="5rd-jg-Oh0" secondAttribute="bottom" priority="500" constant="74" id="tVb-7S-rd8">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="0ZS-PD-jbN" firstAttribute="top" secondItem="6m2-Pk-kEx" secondAttribute="bottom" constant="74" id="vsN-ff-49R">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="usZ-hA-14r" firstAttribute="top" secondItem="cw2-8u-Yru" secondAttribute="top" constant="-14" id="wTg-lt-fKa">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="bottom" secondItem="kdc-al-Dgu" secondAttribute="bottom" id="wUx-ey-X83"/>
<constraint firstItem="6ck-rH-HPa" firstAttribute="centerY" secondItem="Ot4-pt-BUj" secondAttribute="centerY" id="x9y-Hj-PR6"/>
<constraint firstItem="fVE-zT-baW" firstAttribute="centerX" secondItem="nGh-s6-UA5" secondAttribute="centerX" id="xfs-hW-X9O"/>
<constraint firstItem="kdc-al-Dgu" firstAttribute="top" secondItem="nGh-s6-UA5" secondAttribute="top" id="zjC-bZ-e5Y"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="nGh-s6-UA5" firstAttribute="trailing" secondItem="aSd-tu-AKa" secondAttribute="trailing" id="HXu-Ht-MlO"/>
<constraint firstItem="nGh-s6-UA5" firstAttribute="leading" secondItem="aSd-tu-AKa" secondAttribute="leading" id="JE7-jL-185"/>
<constraint firstItem="nGh-s6-UA5" firstAttribute="top" secondItem="aSd-tu-AKa" secondAttribute="top" id="Jog-e3-a36"/>
<constraint firstItem="nGh-s6-UA5" firstAttribute="width" secondItem="g92-EX-OdQ" secondAttribute="width" id="rem-Dp-P4v"/>
<constraint firstItem="nGh-s6-UA5" firstAttribute="bottom" secondItem="aSd-tu-AKa" secondAttribute="bottom" id="x3L-0x-fgi"/>
</constraints>
<viewLayoutGuide key="contentLayoutGuide" id="aSd-tu-AKa"/>
<viewLayoutGuide key="frameLayoutGuide" id="g92-EX-OdQ"/>
</scrollView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Zrl-aI-cae">
<rect key="frame" x="317" y="24" width="42" height="42"/>
<constraints>
<constraint firstAttribute="width" constant="42" id="8Vw-5K-3gU"/>
<constraint firstAttribute="height" constant="42" id="caJ-4U-tpY"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" backgroundImage="IAP Out'logo"/>
<connections>
<action selector="dismissClick:" destination="-1" eventType="touchUpInside" id="Sr0-ot-Cfs"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Zrl-aI-cae" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="4" id="1Hm-Td-tsh">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="bottom" secondItem="BnJ-Xo-PqP" secondAttribute="bottom" id="3Ef-ge-xiV"/>
<constraint firstItem="5rd-jg-Oh0" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" multiplier="0.898667" id="AX5-Ce-xzb"/>
<constraint firstItem="BnJ-Xo-PqP" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="GtA-xD-gPQ"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Zrl-aI-cae" secondAttribute="trailing" constant="16" id="Iqb-vj-BRx">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="BnJ-Xo-PqP" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="Jhk-KI-R1D"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="BnJ-Xo-PqP" secondAttribute="trailing" id="oUl-QC-ajw"/>
</constraints>
<point key="canvasLocation" x="130.40000000000001" y="-13.043478260869566"/>
</view>
</objects>
<resources>
<image name="IAP AD'logo" width="24" height="24"/>
<image name="IAP B'bg" width="375" height="812"/>
<image name="IAP Choose'logo" width="337" height="69"/>
<image name="IAP Dn'logo" width="24" height="24"/>
<image name="IAP Mu'logo" width="24" height="24"/>
<image name="IAP Out'logo" width="42" height="42"/>
<image name="IAP Save'bg" width="87" height="27"/>
<image name="No mandatory'logo" width="16" height="16"/>
<image name="Rights'logo" width="229" height="149"/>
</resources>
</document>

View File

@ -121,6 +121,7 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
private func switchAOrBAction() {
//B
guard UserDefaults.standard.bool(forKey: "MP_Into_B") != true else {
MP_IAPManager.shared.startLunchStatus()
//
MP_AnalyticsManager.shared.getOpenStatus { [weak self] open in
if open {
@ -166,6 +167,7 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
MP_NetWorkManager.shared.performTaskNetWrokAvailable {
[weak self] in
guard let self = self else {return}
MP_IAPManager.shared.startLunchStatus()
//
MP_AnalyticsManager.shared.getOpenStatus { [weak self] open in
guard let self = self else {return}

View File

@ -46,3 +46,37 @@ extension Range where Bound == String.Index {
return NSRange(location: utf16IndexStart, length: utf16IndexEnd - utf16IndexStart)
}
}
///UILabel
extension UILabel {
///
func setGradientTextColor(_ colors:[CGColor]) {
self.layoutIfNeeded()
//
let gradientLayer = CAGradientLayer()
gradientLayer.colors = colors
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
gradientLayer.frame = self.bounds
//
let textLayer = CATextLayer()
textLayer.frame = self.bounds
textLayer.string = self.attributedText
textLayer.isWrapped = true
textLayer.truncationMode = .end
textLayer.alignmentMode = .center
textLayer.contentsScale = UIScreen.main.scale
gradientLayer.mask = textLayer
//
self.layer.addSublayer(gradientLayer)
}
///
func cleanGradientTextColor() {
self.layoutIfNeeded()
//
for item in layer.sublayers ?? [] {
if item is CAGradientLayer {
item.removeFromSuperlayer()
}
}
}
}

View File

@ -75,6 +75,10 @@ let offline_songBGImage:UIImage = UIImage(named: "Offline Songs")!
let privacyUrl:URL = .init(string: "https://musiclax.mystrikingly.com/privacy")!
///
let serviceUrl:URL = .init(string: "https://musiclax.mystrikingly.com/terms")!
///
let gradientTextColors:[CGColor] = [UIColor(red: 0, green: 0.863, blue: 1, alpha: 1).cgColor,
UIColor(red: 0, green: 1, blue: 0.561, alpha: 1).cgColor,
UIColor(red: 0.776, green: 1, blue: 0.639, alpha: 1).cgColor]
//MARK: -
//

View File

@ -15,6 +15,14 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
private let sharedInstance = GADMobileAds.sharedInstance()
///广
private var openAdStatus:Bool = true
///广
func setOpenAdStatus(_ bool:Bool) {
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
openAdStatus = bool
}
}
///广(50)
private let expirationTime:TimeInterval = 3000
@ -753,7 +761,10 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
var completePlayInterstitialAdBlock:(() -> Void)?
//广
func loadPlayInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
guard openAdStatus else {return}
guard openAdStatus else {
completion(false)
return
}
// 广广
if isLoadingPlayInterstitialAd || isPlayInterstitialAdAvailable() {
// 广广
@ -802,7 +813,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
}
///广
func showPlayInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) {
guard openAdStatus else {return}
guard openAdStatus else {
return
}
// 广广广
guard !interstitialSwitch, !isShowingPlayInterstitialAd else { return }
//
@ -869,7 +882,10 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
var completeSwitchInterstitialAdBlock:(() -> Void)?
//广
func loadSwitchInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
guard openAdStatus else {return}
guard openAdStatus else {
completion(false)
return
}
// 广广
if isLoadingSwitchInterstitialAd || isSwitchInterstitialAdAvailable() {
// 广广
@ -917,7 +933,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
}
///广
func showSwitchInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) {
guard openAdStatus else {return}
guard openAdStatus else {
return
}
// 广广广
guard !interstitialSwitch, !isShowingSwitchInterstitialAd else { return }
//
@ -983,7 +1001,10 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
var completeLoadInterstitialAdBlock:(() -> Void)?
//广
func loadLoadInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
guard openAdStatus else {return}
guard openAdStatus else {
completion(false)
return
}
// 广广
if isLoadingLoadInterstitialAd || isLoadInterstitialAdAvailable() {
// 广广
@ -1031,7 +1052,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
}
///广
func showLoadInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) {
guard openAdStatus else {return}
guard openAdStatus else {
return
}
// 广广广
guard !interstitialSwitch, !isShowingLoadInterstitialAd else { return }
//
@ -1116,7 +1139,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
var onLibraryNativeAdBlock:(() -> Void)?
///广
func configureLibraryNativeAd(rootController vc:UIViewController) {
guard openAdStatus else {return}
guard openAdStatus else {
return
}
if libraryViewController == nil {
libraryViewController = vc
}
@ -1222,7 +1247,10 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
}
//广
func loadLibraryInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
guard openAdStatus else {return}
guard openAdStatus else {
completion(false)
return
}
// 广广
if isLoadingLibraryInterstitialAd || isLibraryInterstitialAdAvailable() {
// 广广
@ -1270,7 +1298,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
}
///广
func showLibraryInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) {
guard openAdStatus else {return}
guard openAdStatus else {
return
}
// 广广广
guard !interstitialSwitch, !isShowingLibraryInterstitialAd else { return }
//
@ -1339,7 +1369,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
var completeGlobalInterstitialAdBlock:(() -> Void)?
//广
func loadGlobalInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
guard openAdStatus else {return}
guard openAdStatus else {
return
}
// 广广
if isLoadingGlobalInterstitialAd || isGlobalInterstitialAdAvailable() {
// 广广
@ -1375,7 +1407,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont
}
///广
func showGlobalInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) {
guard openAdStatus else {return}
guard openAdStatus else {
return
}
// 广广广
guard !interstitialSwitch, !isShowingGlobalInterstitialAd else { return }
//

View File

@ -144,6 +144,28 @@ class MP_AnalyticsManager: NSObject {
}
MP_AdMobManager.shared.reloadAdMobIDs()
}
//
if let trashLists = self.remoteConfig.configValue(forKey: "trashLists").jsonValue as? [String:Any], let lists = trashLists["lists"] as? [[String:Any]] {
//
var array:[MPPositive_TrashListModel] = lists.map({.init($0)})
array = array.filter({$0.statu == true})
//
var trashKeyWords:[String] = []
var trashSingerIDs:[String] = []
var trashVideoIDs:[String] = []
array.forEach { item in
trashKeyWords.append(contentsOf: item.keyWords)
trashSingerIDs.append(item.singerID)
trashVideoIDs.append(contentsOf: item.videoIDs)
}
//
trashKeyWords = trashKeyWords.filter({$0.isEmpty == false})
MP_NetWorkManager.shared.setTrashKeyWords(trashKeyWords)
trashSingerIDs = trashSingerIDs.filter({$0.isEmpty == false})
MP_NetWorkManager.shared.setTrashSingerIds(trashSingerIDs)
trashVideoIDs = trashVideoIDs.filter({$0.isEmpty == false})
MP_NetWorkManager.shared.setTrashVideoIds(trashVideoIDs)
}
//
if let versionData = self.remoteConfig.configValue(forKey: "dataVersion").jsonValue as? [String:String] {
//
@ -786,3 +808,4 @@ class MP_AnalyticsManager: NSObject {
return losAngelesTimeString
}
}

View File

@ -10,9 +10,9 @@ import StoreKit
///
class MP_IAPManager: NSObject {
///
let shared = MP_IAPManager()
static let shared = MP_IAPManager()
///ID
private var productIdentifiers:[String] = ["6587553652","6587553795","6587554369"]
private var productIdentifiers:[String] = ["1weekvip","1yearvip","lifetimevip"]
///(ID)
private var productsRequest:SKProductsRequest?
///
@ -20,13 +20,22 @@ class MP_IAPManager: NSObject {
override init() {
super.init()
SKPaymentQueue.default().add(self)
}
//
deinit {
SKPaymentQueue.default().remove(self)
}
///
func requestProducts() {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
//
print("无网络状况,无法获得产品")
return
}
//
availableProducts = []
//IDSet
var setStrings:Set<String> = Set(productIdentifiers)
let setStrings:Set<String> = Set(productIdentifiers)
//
productsRequest = SKProductsRequest(productIdentifiers: setStrings)
//
@ -34,11 +43,73 @@ class MP_IAPManager: NSObject {
//
productsRequest?.start()
}
///
func purchaseProduct(_ index:Int) {
//
guard availableProducts.indices.contains(index) else {
//广
MP_HUD.onlytext("Try again!", delay: 1.0, completion: nil)
requestProducts()
return
}
let id = productIdentifiers[index]
if let product = availableProducts.first(where: {$0.productIdentifier == id}) {
//
let payment = SKPayment(product: product)
//线
SKPaymentQueue.default().add(payment)
MP_HUD.loading()
}
}
///
func restorePurchases() {
MP_HUD.loading()
//
SKPaymentQueue.default().restoreCompletedTransactions()
}
///
func systemRestorePurchases() {
let receiptURL = Bundle.main.appStoreReceiptURL
guard let receipt = try? Data(contentsOf: receiptURL!) else {
//
print("没有收据,广告默认开")
//AppStore,使广
MP_AdMobManager.shared.setOpenAdStatus(true)
return
}
//
SKPaymentQueue.default().restoreCompletedTransactions()
}
///广
func startLunchStatus() {
//
let receiptURL = Bundle.main.appStoreReceiptURL
guard let receipt = try? Data(contentsOf: receiptURL!) else {
//
print("没有收据,广告默认开")
//AppStore,使广
MP_AdMobManager.shared.setOpenAdStatus(true)
return
}
//
print("有收据,开始检索本地信息")
reloadOpenStatus()
}
///广
func reloadOpenStatus() {
//广
if isProductPurchased(productId: productIdentifiers[0]) || isProductPurchased(productId: productIdentifiers[1]) || isProductPurchased(productId: productIdentifiers[2]){
//广
MP_AdMobManager.shared.setOpenAdStatus(false)
}else {
MP_AdMobManager.shared.setOpenAdStatus(true)
}
}
}
//MARK: - SKProductsRequestDelegate
extension MP_IAPManager: SKProductsRequestDelegate {
//
extension MP_IAPManager: SKProductsRequestDelegate, SKPaymentTransactionObserver {
///
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
//
availableProducts = response.products
@ -48,5 +119,175 @@ extension MP_IAPManager: SKProductsRequestDelegate {
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_AdMobManager.shared.setOpenAdStatus(true)
}
}
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: any Error) {
print("重启交易失败")
MP_HUD.error("The current transaction failed, \(error.localizedDescription)", delay: 1.0, completion: nil)
//VIP
productIdentifiers.forEach { item in
cleanPurchase(productId: item)
}
MP_AdMobManager.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.")
//
self.storePurchase(productId: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
//广
reloadOpenStatus()
}
//
private func restore(transaction: SKPaymentTransaction) {
print("Transaction restored.")
//
self.storePurchase(productId: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
//广
reloadOpenStatus()
}
///
private func fail(transaction: SKPaymentTransaction) {
//
if let error = transaction.error as NSError? {
if error.code != SKError.paymentCancelled.rawValue {
MP_HUD.error("The current transaction failed, \(error.localizedDescription)", delay: 1.0, completion: nil)
} else {
MP_HUD.onlytext("The current transaction has been canceled", 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] {
print("Receipt validation response: \(jsonResponse)")
//
completion(true)
} else {
completion(false)
}
} catch {
completion(false)
}
}
task.resume()
} catch {
completion(false)
}
}
}

View File

@ -83,6 +83,26 @@ class MP_NetWorkManager: NSObject {
private let codes:[String] = [
"CL","GB","ID","IN","IT","IL","HU","NZ","ES","UY","UA","UG","GT","TR","TZ","SA","RS","SV","CH","SE","JP","PT","NO","NG","NI","ZA","MX","PE","US","RO","LU","KE","ZW","CZ","CA","HN","NL","KR","CR","CO","FI","FR","EC","RU","DO","DK","BO","PL","IS","BE","BR","PA","PY","AU","AT","EE","IE","EG","AE","AR","ZZ"
]
///
private var trashKeyWords:[String] = []
///
func setTrashKeyWords(_ words:[String]){
trashKeyWords = words
}
///id
private var trashSingerIds:[String] = []
///
func setTrashSingerIds(_ ids:[String]) {
trashSingerIds = ids
}
///id
private var trashVideoIds:[String] = []
///
func setTrashVideoIds(_ ids:[String]) {
trashVideoIds = ids
}
///
private var isAllowedDownload:Bool = true
//
enum NetWorkStatus: String {
case notReachable = "网络不可用"
@ -1237,6 +1257,15 @@ extension MP_NetWorkManager {
print("Url is Incorrect")
return
}
//
guard trashKeyWords.contains(text) == false else {
//
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
print("是禁用关键词")
completion([])
}
return
}
//
let parameters:[String:Any] = [
"query":text,
@ -1537,8 +1566,8 @@ extension MP_NetWorkManager {
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
browse.items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
browse.items.append(.init(d))
}
})
browses.append(browse)
@ -1618,8 +1647,8 @@ extension MP_NetWorkManager {
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
browse.items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
browse.items.append(.init(d))
}
})
browses.append(browse)
@ -1649,8 +1678,8 @@ extension MP_NetWorkManager {
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
items.append(.init(d))
}
})
}else if let musicShelfRenderer = content.musicShelfRenderer{
@ -1660,8 +1689,8 @@ extension MP_NetWorkManager {
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
items.append(.init(d))
}
})
}
@ -1681,8 +1710,8 @@ extension MP_NetWorkManager {
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
items.append(.init(d))
}
})
}else if let musicShelfRenderer = content.musicShelfRenderer{
@ -1692,8 +1721,8 @@ extension MP_NetWorkManager {
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
items.append(.init(d))
}
})
}
@ -1785,8 +1814,8 @@ extension MP_NetWorkManager {
params = musicCarouselShelfRenderer.header?.musicCarouselShelfBasicHeaderRenderer?.title?.runs?.first?.navigationEndpoint?.browseEndpoint?.params
//
musicCarouselShelfRenderer.contents?.forEach({ item in
if item.musicTwoRowItemRenderer != nil {
itemViews.append(.init(parsingMusicTwoRowItemRenderer(item.musicTwoRowItemRenderer!)))
if let musicTwoRowItemRenderer = item.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
itemViews.append(.init(d))
}
})
}
@ -1817,8 +1846,8 @@ extension MP_NetWorkManager {
if let gridRenderer = content.gridRenderer {
//
gridRenderer.items?.forEach({ item in
if let musicTwoRowItemRenderer = item.musicTwoRowItemRenderer {
array.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
if let musicTwoRowItemRenderer = item.musicTwoRowItemRenderer, let d = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
array.append(.init(d))
}
continuation = gridRenderer.continuations?.first?.nextContinuationData?.continuation
clickTrackingParams = gridRenderer.continuations?.first?.nextContinuationData?.clickTrackingParams
@ -1928,7 +1957,9 @@ extension MP_NetWorkManager {
browse.items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
if let item = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
browse.items.append(.init(item))
}
}
})
if browse.items.isEmpty != true {
@ -1943,7 +1974,9 @@ extension MP_NetWorkManager {
browse.items.append(.init(item))
}
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
if let item = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
browse.items.append(.init(item))
}
}
})
if browse.items.isEmpty != true {
@ -2109,9 +2142,10 @@ extension MP_NetWorkManager {
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
list.items.append(.init(item))
}
}else if content.musicTwoRowItemRenderer != nil {
let item = parsingMusicTwoRowItemRenderer(content.musicTwoRowItemRenderer!)
list.items.append(.init(item))
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer{
if let item = parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer) {
list.items.append(.init(item))
}
}
})
sectionLists.append(list)
@ -2213,49 +2247,54 @@ extension MP_NetWorkManager {
if let contents = musicCardShelfRenderer.contents {
contents.forEach { content in
//
let item = MPPositive_BrowseItemModel()
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer, (musicResponsiveListItemRenderer.playlistItemData != nil || musicResponsiveListItemRenderer.navigationEndpoint != nil) && (musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE"){
if let trackingParams = musicResponsiveListItemRenderer.trackingParams {
item.clickTrackingParams = trackingParams
}
//
item.coverUrls = musicResponsiveListItemRenderer.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
//
for (index, flexColumn) in (musicResponsiveListItemRenderer.flexColumns ?? []).enumerated() {
if index == 0 {
//
item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
}else {
//
item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
}
}
item.playListId = musicResponsiveListItemRenderer.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
//id
if musicResponsiveListItemRenderer.playlistItemData != nil {
//
item.itemType = .single
item.videoId = musicResponsiveListItemRenderer.playlistItemData?.videoId
}else {
///
item.browseId = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseId
let pageType = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseId
//
item.itemType = .artist
}else {
///
item.itemType = .list
}
}
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer, let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
if item.title != nil && item.itemType != nil, item.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
resultList.previewItemViews.append(.init(item))
}
}
if item.title != nil && item.itemType != nil, item.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
resultList.previewItemViews.append(.init(item))
}
// let item = MPPositive_BrowseItemModel()
// if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer, (musicResponsiveListItemRenderer.playlistItemData != nil || musicResponsiveListItemRenderer.navigationEndpoint != nil) && (musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE"){
// if let trackingParams = musicResponsiveListItemRenderer.trackingParams {
// item.clickTrackingParams = trackingParams
// }
// //
// item.coverUrls = musicResponsiveListItemRenderer.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
// //
// for (index, flexColumn) in (musicResponsiveListItemRenderer.flexColumns ?? []).enumerated() {
// if index == 0 {
// //
// item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
// }else {
// //
// item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
// }
// }
// item.playListId = musicResponsiveListItemRenderer.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
// //id
// if musicResponsiveListItemRenderer.playlistItemData != nil {
// //
// item.itemType = .single
// item.videoId = musicResponsiveListItemRenderer.playlistItemData?.videoId
// }else {
// ///
// item.browseId = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseId
// let pageType = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
// if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
// //
// if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
// item.artistId = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseId
// //
// item.itemType = .artist
// }else {
// ///
// item.itemType = .list
// }
// }
// }
// }
// if item.title != nil && item.itemType != nil, item.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
// resultList.previewItemViews.append(.init(item))
// }
}
}
//,queryparams
@ -2285,6 +2324,13 @@ extension MP_NetWorkManager {
return item.item.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE"
})
}
//
resultListSections.forEach { list in
list.previewItemViews = list.previewItemViews.filter({ item in
return (trashSingerIds.contains(item.item.artistId ?? "") == false) && (trashVideoIds.contains(item.item.videoId ?? "") == false)
})
}
resultListSections = resultListSections.filter({$0.previewItemViews.count != 0})
return resultListSections
}
@ -2296,47 +2342,52 @@ extension MP_NetWorkManager {
contents.forEach({ content in
/////
let item = MPPositive_BrowseItemModel()
if (content.musicResponsiveListItemRenderer?.playlistItemData != nil || content.musicResponsiveListItemRenderer?.navigationEndpoint != nil) && (content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE") {
//
item.coverUrls = content.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
//
for (index, flexColumn) in (content.musicResponsiveListItemRenderer?.flexColumns ?? []).enumerated() {
if index == 0 {
//
item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
}else {
//
item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
}
}
item.playListId = content.musicResponsiveListItemRenderer?.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
//id
if content.musicResponsiveListItemRenderer?.playlistItemData != nil {
//
item.itemType = .single
item.videoId = content.musicResponsiveListItemRenderer?.playlistItemData?.videoId
}else {
///
item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
//
item.itemType = .artist
}else {
///
item.itemType = .list
}
}
}
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer, let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
//
if item.itemType != nil {
array.append(.init(item))
}
}
// if (content.musicResponsiveListItemRenderer?.playlistItemData != nil || content.musicResponsiveListItemRenderer?.navigationEndpoint != nil) && (content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE") {
// //
// item.coverUrls = content.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
// //
// for (index, flexColumn) in (content.musicResponsiveListItemRenderer?.flexColumns ?? []).enumerated() {
// if index == 0 {
// //
// item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
// }else {
// //
// item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
// }
// }
// item.playListId = content.musicResponsiveListItemRenderer?.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
// //id
// if content.musicResponsiveListItemRenderer?.playlistItemData != nil {
// //
// item.itemType = .single
// item.videoId = content.musicResponsiveListItemRenderer?.playlistItemData?.videoId
// }else {
// ///
// item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
// let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
// if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
// //
// if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
// item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
// //
// item.itemType = .artist
// }else {
// ///
// item.itemType = .list
// }
// }
// }
// //
// if item.itemType != nil {
// array.append(.init(item))
// }
// }
})
}
var continuation:String?
@ -2346,6 +2397,9 @@ extension MP_NetWorkManager {
continuation = continuations.nextContinuationData?.continuation
clickTrackingParams = continuations.nextContinuationData?.clickTrackingParams
}
array = array.filter({ item in
return (trashSingerIds.contains(item.item.artistId ?? "") == false) && (trashVideoIds.contains(item.item.videoId ?? "") == false)
})
array = array.filter({$0.item.itemType != nil})
return (array, continuation, clickTrackingParams)
}
@ -2355,46 +2409,52 @@ extension MP_NetWorkManager {
if let contents = musicShelfContinuation.contents {
///
contents.forEach({ content in
/////
let item = MPPositive_BrowseItemModel()
//
item.coverUrls = content.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
//
for (index, flexColumn) in (content.musicResponsiveListItemRenderer?.flexColumns ?? []).enumerated() {
if index == 0 {
//
item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
}else {
//
item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer, let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
//
if item.itemType != nil {
array.append(.init(item))
}
}
item.playListId = content.musicResponsiveListItemRenderer?.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
//id
if content.musicResponsiveListItemRenderer?.playlistItemData != nil {
//
item.itemType = .single
item.videoId = content.musicResponsiveListItemRenderer?.playlistItemData?.videoId
}else {
///
item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
//
item.itemType = .artist
}else {
///
item.itemType = .list
}
}
}
//
if item.itemType != nil {
array.append(.init(item))
}
// /////
// let item = MPPositive_BrowseItemModel()
// //
// item.coverUrls = content.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
// //
// for (index, flexColumn) in (content.musicResponsiveListItemRenderer?.flexColumns ?? []).enumerated() {
// if index == 0 {
// //
// item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
// }else {
// //
// item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
// }
// }
// item.playListId = content.musicResponsiveListItemRenderer?.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
// //id
// if content.musicResponsiveListItemRenderer?.playlistItemData != nil {
// //
// item.itemType = .single
// item.videoId = content.musicResponsiveListItemRenderer?.playlistItemData?.videoId
// }else {
// ///
// item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
// let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
// if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
// //
// if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
// item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
// //
// item.itemType = .artist
// }else {
// ///
// item.itemType = .list
// }
// }
// }
// //
// if item.itemType != nil {
// array.append(.init(item))
// }
})
}
var continuation:String?
@ -2404,6 +2464,9 @@ extension MP_NetWorkManager {
continuation = continuations.nextContinuationData?.continuation
clickTrackingParams = continuations.nextContinuationData?.clickTrackingParams
}
array = array.filter({ item in
return (trashSingerIds.contains(item.item.artistId ?? "") == false) && (trashVideoIds.contains(item.item.videoId ?? "") == false)
})
array = array.filter({$0.item.itemType != nil})
return (array, continuation, clickTrackingParams)
}
@ -2412,7 +2475,6 @@ extension MP_NetWorkManager {
private func parsingMusicResponsiveListItemRenderer(_ musicResponsiveListItemRenderer: RootMusicResponsiveListItemRenderer) -> MPPositive_BrowseItemModel? {
//
let item = MPPositive_BrowseItemModel()
//
item.coverUrls = musicResponsiveListItemRenderer.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.compactMap({$0.url})
if let clickTrackingParams = musicResponsiveListItemRenderer.trackingParams {
@ -2424,7 +2486,7 @@ extension MP_NetWorkManager {
item.itemType = .single
item.videoId = playlistItemData.videoId
//
guard var flexColumns = musicResponsiveListItemRenderer.flexColumns, flexColumns.isEmpty != true else {
guard var flexColumns = musicResponsiveListItemRenderer.flexColumns, flexColumns.isEmpty == false else {
return nil
}
//,VideoId,PlayListId,pageTypeflexColumn
@ -2441,16 +2503,33 @@ extension MP_NetWorkManager {
///
flexColumns.forEach { flexColumn in
item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
if let ari = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.first(where: {$0.navigationEndpoint?.browseEndpoint != nil}) {
if ari.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType == "MUSIC_PAGE_TYPE_ARTIST", let id = ari.navigationEndpoint?.browseEndpoint?.browseId {
//ID
item.artistId = id
}
}
}
//videoId,playListId,playListId使
guard (item.playListId ?? "").isEmpty == true else {
//
return item
//
if (trashSingerIds.contains(item.artistId ?? "")) == false && (trashVideoIds.contains(item.videoId ?? "")) == false {
return item
}else {
//
return nil
}
}
//
if let watchItem = musicResponsiveListItemRenderer.menu?.menuRenderer?.items?.first(where: {$0.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint != nil}) {
item.playListId = watchItem.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
return item
//
if (trashSingerIds.contains(item.artistId ?? "")) == false && (trashVideoIds.contains(item.videoId ?? "")) == false {
return item
}else {
//
return nil
}
}else {
//
return nil
@ -2470,6 +2549,12 @@ extension MP_NetWorkManager {
///
flexColumns.forEach { flexColumn in
item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
if let ari = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.first(where: {$0.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType == "MUSIC_PAGE_TYPE_ARTIST"}) {
//ID
if let id = ari.navigationEndpoint?.browseEndpoint?.browseId {
item.artistId = id
}
}
}
//Id
guard let browseEndpoint = navigationEndpoint.browseEndpoint else {
@ -2490,7 +2575,12 @@ extension MP_NetWorkManager {
}else if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
//
item.itemType = .artist
return item
item.artistId = item.browseId
if (trashSingerIds.contains(item.artistId ?? "")) == false {
return item
}else {
return nil
}
}else {
return nil
}
@ -2499,7 +2589,7 @@ extension MP_NetWorkManager {
}
}
//musicResponsiveListItemRenderer
private func parsingMusicTwoRowItemRenderer(_ musicTwoRowItemRenderer: RootMusicTwoRowItemRenderer) -> MPPositive_BrowseItemModel {
private func parsingMusicTwoRowItemRenderer(_ musicTwoRowItemRenderer: RootMusicTwoRowItemRenderer) -> MPPositive_BrowseItemModel? {
//
let item = MPPositive_BrowseItemModel()
//
@ -2508,6 +2598,10 @@ extension MP_NetWorkManager {
item.title = musicTwoRowItemRenderer.title?.runs?.reduce("", { $0 + ($1.text ?? "")})
//
item.subtitle = musicTwoRowItemRenderer.subtitle?.runs?.reduce("", { $0 + ($1.text ?? "")})
//
if let art = musicTwoRowItemRenderer.subtitle?.runs?.first(where: {$0.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType == "MUSIC_PAGE_TYPE_ARTIST"}) {
item.artistId = art.navigationEndpoint?.browseEndpoint?.browseId
}
if let clickTrackingParams = musicTwoRowItemRenderer.navigationEndpoint?.clickTrackingParams {
item.clickTrackingParams = clickTrackingParams
}
@ -2533,7 +2627,11 @@ extension MP_NetWorkManager {
item.browseId = browseEndpoint.browseId
}
}
return item
if (trashSingerIds.contains(item.artistId ?? "")) == false {
return item
}else {
return nil
}
}
}
//MARK: -

View File

@ -659,6 +659,8 @@ struct RootMusicResponsiveListItemRenderer: Codable {
let text:String?
///
let navigationEndpoint:NavigationEndpoint?
enum CodingKeys: String, CodingKey {
case text = "text"
case navigationEndpoint = "navigationEndpoint"
@ -674,14 +676,18 @@ struct RootMusicResponsiveListItemRenderer: Codable {
let clickTrackingParams:String?
///
let watchEndpoint:WatchEndpoint?
///
let browseEndpoint:BrowseEndpoint?
enum CodingKeys: String, CodingKey {
case clickTrackingParams = "clickTrackingParams"
case watchEndpoint = "watchEndpoint"
case browseEndpoint = "browseEndpoint"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
clickTrackingParams = try values.decodeIfPresent(String.self, forKey: .clickTrackingParams)
watchEndpoint = try values.decodeIfPresent(WatchEndpoint.self, forKey: .watchEndpoint)
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
}
//
struct WatchEndpoint: Codable {
@ -724,6 +730,41 @@ struct RootMusicResponsiveListItemRenderer: Codable {
}
}
}
//
struct BrowseEndpoint: Codable {
let browseId:String?
let browseEndpointContextSupportedConfigs:BrowseEndpointContextSupportedConfigs?
enum CodingKeys: String, CodingKey {
case browseId = "browseId"
case browseEndpointContextSupportedConfigs = "browseEndpointContextSupportedConfigs"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
browseId = try values.decodeIfPresent(String.self, forKey: .browseId)
browseEndpointContextSupportedConfigs = try values.decodeIfPresent(BrowseEndpointContextSupportedConfigs.self, forKey: .browseEndpointContextSupportedConfigs)
}
struct BrowseEndpointContextSupportedConfigs: Codable {
let browseEndpointContextMusicConfig:BrowseEndpointContextMusicConfig?
enum CodingKeys: String, CodingKey {
case browseEndpointContextMusicConfig = "browseEndpointContextMusicConfig"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
browseEndpointContextMusicConfig = try values.decodeIfPresent(BrowseEndpointContextMusicConfig.self, forKey: .browseEndpointContextMusicConfig)
}
struct BrowseEndpointContextMusicConfig: Codable {
let pageType:String?
enum CodingKeys: String, CodingKey {
case pageType = "pageType"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
pageType = try values.decodeIfPresent(String.self, forKey: .pageType)
}
}
}
}
}
}
}
@ -984,13 +1025,59 @@ struct RootMusicTwoRowItemRenderer: Codable {
}
struct Run: Codable {
let text:String?
let navigationEndpoint:NavigationEndpoint?
enum CodingKeys: String, CodingKey {
case text = "text"
case navigationEndpoint = "navigationEndpoint"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
text = try values.decodeIfPresent(String.self, forKey: .text)
navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint)
}
struct NavigationEndpoint: Codable {
let browseEndpoint:BrowseEndpoint?
enum CodingKeys: String, CodingKey {
case browseEndpoint = "browseEndpoint"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
}
struct BrowseEndpoint: Codable {
let browseId:String?
let browseEndpointContextSupportedConfigs:BrowseEndpointContextSupportedConfigs?
enum CodingKeys: String, CodingKey {
case browseId = "browseId"
case browseEndpointContextSupportedConfigs = "browseEndpointContextSupportedConfigs"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
browseId = try values.decodeIfPresent(String.self, forKey: .browseId)
browseEndpointContextSupportedConfigs = try values.decodeIfPresent(BrowseEndpointContextSupportedConfigs.self, forKey: .browseEndpointContextSupportedConfigs)
}
struct BrowseEndpointContextSupportedConfigs: Codable {
let browseEndpointContextMusicConfig:BrowseEndpointContextMusicConfig?
enum CodingKeys: String, CodingKey {
case browseEndpointContextMusicConfig = "browseEndpointContextMusicConfig"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
browseEndpointContextMusicConfig = try values.decodeIfPresent(BrowseEndpointContextMusicConfig.self, forKey: .browseEndpointContextMusicConfig)
}
struct BrowseEndpointContextMusicConfig: Codable {
let pageType:String?
enum CodingKeys: String, CodingKey {
case pageType = "pageType"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
pageType = try values.decodeIfPresent(String.self, forKey: .pageType)
}
}
}
}
}
}
}

View File

@ -0,0 +1,40 @@
//
// MPPositive_TrashListModel.swift
// relax.offline.mp3.music
//
// Created by Mr.Zhou on 2024/7/31.
//
import UIKit
///
class MPPositive_TrashListModel: NSObject {
///
var statu:Bool = false
///
var name:String = ""
///
var keyWords:[String] = []
///ID
var singerID:String = ""
///ID
var videoIDs:[String] = []
init(_ dict:[String:Any]) {
super.init()
if let statu = dict["statu"] as? Bool {
self.statu = statu
}
if let name = dict["name"] as? String {
self.name = name
}
if let keyWords = dict["keyWords"] as? [String] {
self.keyWords = keyWords
}
if let singerID = dict["singerID"] as? String{
self.singerID = singerID
}
if let videoIDs = dict["videoIDs"] as? [String]{
self.videoIDs = videoIDs
}
}
}

View File

@ -15,8 +15,8 @@ class MPPositive_RecommendLoadViewModel: NSObject {
[weak self] in
guard let self = self else {return}
//
if resultReloadBlock != nil {
resultReloadBlock!()
if let block = resultReloadBlock {
block()
}
}
}

View File

@ -15,8 +15,8 @@ class MPPositive_SearchResultsLoadViewModel: NSObject {
[weak self] in
guard let self = self else {return}
//
if resultReloadBlock != nil {
resultReloadBlock!()
if let block = resultReloadBlock {
block()
}
}
}
@ -43,7 +43,9 @@ class MPPositive_SearchResultsLoadViewModel: NSObject {
}
}
MP_NetWorkManager.shared.requestSearchPreviewResults(text) { [weak self] results in
self?.sectionLists = results
guard let self = self else {return}
MP_HUD.hideNow()
sectionLists = results
}
}
}

View File

@ -21,6 +21,29 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro
btn.addTarget(self, action: #selector(menuRightClick(_ :)), for: .touchUpInside)
return btn
}()
//ViP
private lazy var vipImageView:UIImageView = {
let imageView:UIImageView = UIImageView(image: .init(named: "VIP'logo"))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(vipIAPClick(_ :))))
return imageView
}()
//Label
private lazy var musicLaxLabel:UILabel = {
let label = UILabel()
label.text = "MusicLax"
// Create a bold italic font
if let boldItalicFontDescriptor = UIFont.systemFont(ofSize: 20*width, weight: .bold).fontDescriptor.withSymbolicTraits([.traitBold, .traitItalic]) {
let boldItalicFont = UIFont(descriptor: boldItalicFontDescriptor, size: 20*width)
label.font = boldItalicFont
} else {
label.font = UIFont.boldSystemFont(ofSize: 20*width)
}
label.textColor = .white
return label
}()
//
private lazy var searchView = createSearchView()
//tableView
private lazy var tableView:UITableView = {
let tableView = UITableView(frame: .init(x: 0, y: 0, width: screen_Width, height: screen_Height), style: .plain)
@ -63,6 +86,7 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro
requestTrackingAuthorization { idfa in
}
}
MP_IAPManager.shared.systemRestorePurchases()
setTitle("")
confirgue()
if MPPositive_BrowseLoadViewModel.shared.browseModuleLists.count == 0 {
@ -263,31 +287,55 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro
//MARK: - UI
//
private func confirgue() {
let searchView = createSearchView()
navView.addSubview(searchView)
searchView.snp.makeConstraints { make in
make.width.equalTo(300*width)
make.height.equalTo(32*width)
make.left.equalToSuperview().offset(18*width)
make.centerY.equalToSuperview()
navView.frame = .init(x: 0, y: statusBarHeight, width: screen_Width, height: 90*width)
if memuBtn.superview == nil {
navView.addSubview(memuBtn)
memuBtn.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-16*width)
make.top.equalToSuperview().offset(16*width)
make.width.height.equalTo(24*width)
}
}
view.addSubview(bgImageView)
bgImageView.snp.makeConstraints { make in
make.top.right.left.equalToSuperview()
make.height.equalTo(981*width)
if vipImageView.superview == nil {
navView.addSubview(vipImageView)
vipImageView.snp.makeConstraints { make in
make.centerY.equalTo(memuBtn.snp.centerY)
make.right.equalTo(memuBtn.snp.left).offset(-10*width)
make.width.equalTo(51*width)
make.height.equalTo(32*width)
}
}
view.addSubview(tableView)
navView.addSubview(memuBtn)
memuBtn.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-16*width)
make.centerY.equalToSuperview()
make.width.height.equalTo(24*width)
if musicLaxLabel.superview == nil {
navView.addSubview(musicLaxLabel)
musicLaxLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16*width)
make.centerY.equalTo(memuBtn)
}
musicLaxLabel.setGradientTextColor(gradientTextColors)
}
tableView.snp.makeConstraints { make in
make.top.equalTo(navView.snp.bottom).offset(32*width)
make.left.right.bottom.equalToSuperview()
if searchView.superview == nil {
navView.addSubview(searchView)
searchView.snp.makeConstraints { make in
make.width.equalTo(340*width)
make.height.equalTo(32*width)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-9*width)
}
}
if bgImageView.superview == nil {
view.addSubview(bgImageView)
bgImageView.snp.makeConstraints { make in
make.top.right.left.equalToSuperview()
make.height.equalTo(981*width)
}
}
if tableView.superview == nil {
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.top.equalTo(navView.snp.bottom).offset(15*width)
make.left.right.bottom.equalToSuperview()
}
}
}
//MARK: -
//
@ -315,6 +363,34 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro
setVC.cleanSide = true
navigationController?.pushViewController(setVC, animated: true)
}
//VIP
@objc private func vipIAPClick(_ sender:UITapGestureRecognizer) {
view.endEditing(true)
let iapVC = MP_IAPViewController()
iapVC.isType = true
iapVC.privacyBlock = {
[weak self] in
guard let self = self else {return}
MP_NetWorkManager.shared.requestNetworkPermission(oberve: self) {
[weak self] in
let privacyVC = MPSideA_PrivacyViewController()
self?.navigationController?.pushViewController(privacyVC, animated: true)
}
}
iapVC.termsBlock = {
[weak self] in
guard let self = self else {return}
MP_NetWorkManager.shared.requestNetworkPermission(oberve: self) {
[weak self] in
let serviceVC = MPSideA_ServiceViewController()
self?.navigationController?.pushViewController(serviceVC, animated: true)
}
}
iapVC.modalPresentationStyle = .fullScreen
present(iapVC, animated: true)
}
}
//MARK: - tableView
extension MPPositive_HomeViewController: UITableViewDataSource, UITableViewDelegate {

View File

@ -207,12 +207,14 @@ class MPPositive_ListShowViewController: MPPositive_BaseViewController, UIViewCo
make.left.equalToSuperview().offset(18*width)
make.height.equalTo(32*width)
make.bottom.equalTo(blurView.snp.bottom).offset(-29*width)
// make.width.equalTo(90*width)
}
view.addSubview(shuffleBtn)
shuffleBtn.snp.makeConstraints { make in
make.left.equalTo(playAllBtn.snp.right).offset(18*width)
make.height.equalTo(32*width)
make.centerY.equalTo(playAllBtn)
// make.width.equalTo(90*width)
}
view.addSubview(collectionListBtn)
collectionListBtn.snp.makeConstraints { make in

View File

@ -34,11 +34,10 @@ class MPPositive_SearchResultsShowView: UIView {
}
//
MP_AnalyticsManager.shared.search_result_pvAction()
loadModel.resultReloadBlock = {
loadModel?.resultReloadBlock = {
[weak self] in
//
guard let self = self else {return}
MP_HUD.hideNow()
isHidden = false
MP_AnalyticsManager.shared.search_resultsuccess_actionAction()
if let loadModel = loadModel, let titles = loadModel.sectionLists?.compactMap({$0.title ?? ""}) {

View File

@ -71,7 +71,37 @@ class MPSideA_HomeViewController: MPSideA_BaseViewController {
tableView.reloadData()
}
}
// //
@IBAction func menueClick(_ sender: UIButton) {
let setVC = MPSideA_SettingViewController()
setVC.cleanSide = false
navigationController?.pushViewController(setVC, animated: true)
}
@IBAction func vipClick(_ sender: UIButton) {
view.endEditing(true)
let iapVC = MP_IAPViewController()
iapVC.isType = false
iapVC.privacyBlock = {
[weak self] in
guard let self = self else {return}
MP_NetWorkManager.shared.requestNetworkPermission(oberve: self) {
[weak self] in
let privacyVC = MPSideA_PrivacyViewController()
self?.navigationController?.pushViewController(privacyVC, animated: true)
}
}
iapVC.termsBlock = {
[weak self] in
guard let self = self else {return}
MP_NetWorkManager.shared.requestNetworkPermission(oberve: self) {
[weak self] in
let serviceVC = MPSideA_ServiceViewController()
self?.navigationController?.pushViewController(serviceVC, animated: true)
}
}
iapVC.modalPresentationStyle = .fullScreen
present(iapVC, animated: true)
}
// //
// @objc private func switchPlayerStateAction(_ sender:Notification) {
// //
// tableView.reloadData()

View File

@ -9,7 +9,7 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MPSideA_HomeViewController" customModule="MusicPlayer" customModuleProvider="target">
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MPSideA_HomeViewController" customModule="relax_offline_mp3_music" customModuleProvider="target">
<connections>
<outlet property="tableView" destination="mLK-Jd-vck" id="5mS-bI-6RR"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
@ -31,26 +31,100 @@
</constraints>
</imageView>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="mLK-Jd-vck">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<rect key="frame" x="0.0" y="66" width="375" height="601"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MusicLax" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QKh-4L-ObN">
<rect key="frame" x="16" y="28" width="82.5" height="24"/>
<fontDescription key="fontDescription" type="italicSystem" pointSize="20"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hKx-VM-y2a">
<rect key="frame" x="274" y="24" width="51" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="Mzp-RN-W5s">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="width" constant="51" id="PjR-H8-dch">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" backgroundImage="VIP'logo"/>
<connections>
<action selector="vipClick:" destination="-1" eventType="touchUpInside" id="rpg-qp-peI"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="U4v-5X-SBo">
<rect key="frame" x="335" y="28" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="PPW-Dr-YGv">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstAttribute="height" constant="24" id="dnd-Vm-NoY">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" backgroundImage="Home_Menu'logo"/>
<connections>
<action selector="menueClick:" destination="-1" eventType="touchUpInside" id="R4F-Er-Dfk"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="Cpu-MK-rc5" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="7ZI-Y1-iuM"/>
<constraint firstItem="QKh-4L-ObN" firstAttribute="centerY" secondItem="U4v-5X-SBo" secondAttribute="centerY" id="A36-wN-4KX"/>
<constraint firstItem="Cpu-MK-rc5" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="H3F-G4-wxZ"/>
<constraint firstItem="U4v-5X-SBo" firstAttribute="leading" secondItem="hKx-VM-y2a" secondAttribute="trailing" constant="10" id="IG2-gD-S8V">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="mLK-Jd-vck" secondAttribute="trailing" id="Jdt-xA-aO4"/>
<constraint firstItem="mLK-Jd-vck" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="Pxg-kq-xiW"/>
<constraint firstItem="mLK-Jd-vck" firstAttribute="top" secondItem="hKx-VM-y2a" secondAttribute="bottom" constant="10" id="MDV-kE-cgK">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="QKh-4L-ObN" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="16" id="TWX-Lm-1vU">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Cpu-MK-rc5" secondAttribute="trailing" id="VKw-AA-xMC"/>
<constraint firstItem="hKx-VM-y2a" firstAttribute="centerY" secondItem="U4v-5X-SBo" secondAttribute="centerY" id="cV2-aW-a5z"/>
<constraint firstAttribute="bottom" secondItem="mLK-Jd-vck" secondAttribute="bottom" id="h8k-6P-60E"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="U4v-5X-SBo" secondAttribute="trailing" constant="16" id="hki-di-j4U">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
<constraint firstItem="mLK-Jd-vck" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="nPR-gi-zV7"/>
<constraint firstItem="U4v-5X-SBo" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="8" id="ufo-IS-9AB">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="adapterScreen" value="YES"/>
</userDefinedRuntimeAttributes>
</constraint>
</constraints>
<point key="canvasLocation" x="130.40000000000001" y="-12.143928035982009"/>
</view>
</objects>
<resources>
<image name="Home'bg" width="375" height="900.5"/>
<image name="Home_Menu'logo" width="24" height="24"/>
<image name="VIP'logo" width="51" height="32"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>