B面1.1.5内购提审版
@ -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>";
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP A'bg.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP A'bg.imageset/大背景@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 933 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP A'bg.imageset/大背景@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP AD'logo.imageset/AD图标@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP AD'logo.imageset/AD图标@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP AD'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP B'bg.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP B'bg.imageset/大背景@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 906 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP B'bg.imageset/大背景@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Choose'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Choose'logo.imageset/未选中框@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Choose'logo.imageset/未选中框@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Chooseed'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Chooseed'logo.imageset/选中框@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Chooseed'logo.imageset/选中框@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Dn'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Dn'logo.imageset/下载图标@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Dn'logo.imageset/下载图标@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Mu'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Mu'logo.imageset/音乐图标@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Mu'logo.imageset/音乐图标@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Out'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Out'logo.imageset/btn_square@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 684 B |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Out'logo.imageset/btn_square@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Save'bg.imageset/85_@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Save'bg.imageset/85_@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/IAP Save'bg.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
22
relax.offline.mp3.music/Assets.xcassets/IAP/No mandatory'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/No mandatory'logo.imageset/盾@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 834 B |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/No mandatory'logo.imageset/盾@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/Rights'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/Rights'logo.imageset/Rights@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/Rights'logo.imageset/Rights@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 60 KiB |
22
relax.offline.mp3.music/Assets.xcassets/IAP/VIP'logo.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/VIP'logo.imageset/Group_1597880776@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/IAP/VIP'logo.imageset/Group_1597880776@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
@ -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()
|
||||
//根据isType调整约束(A/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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -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}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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: - 全局变量与方法
|
||||
//存储默认配置值
|
||||
|
||||
@ -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 }
|
||||
//检索是否存在插页间隔时间
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 = []
|
||||
//将产品ID转为Set集合
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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))
|
||||
// }
|
||||
}
|
||||
}
|
||||
//由于是最佳结果模块,所以没有query和params值
|
||||
@ -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,pageType都以第一个flexColumn为主
|
||||
@ -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: - 解析资源加密
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 ?? ""}) {
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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>
|
||||
|
||||