Music_Player3/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift
2024-10-08 17:34:04 +08:00

633 lines
30 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// MPPositive_HomeViewController.swift
// MusicPlayer
//
// Created by Mr.Zhou on 2024/4/19.
//
import UIKit
import MJRefresh
import Lottie
import UserMessagingPlatform
class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewControllerTransitioningDelegate{
//
private lazy var bgImageView:UIImageView = {
let imageView:UIImageView = .init(image: .init(named: "B_Home_BG'bg"))
imageView.contentMode = .scaleAspectFill
return imageView
}()
//
private lazy var memuBtn:UIButton = {
let btn = UIButton()
btn.setBackgroundImage(UIImage(named: "Home_Menu'logo"), for: .normal)
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 HiMelodyLabel:UILabel = {
let label = UILabel()
label.text = "HiMelody"
// 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
label.isUserInteractionEnabled = true
label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(scrollTopAction(_ :))))
return label
}()
//
private lazy var searchView = createSearchView()
//
private var isBuyShow:Bool = true
//
private var lastContentOffset: CGFloat = 0
//
private var isUserDragging:Bool = false
//tableView
private lazy var tableView:UITableView = {
let tableView = UITableView(frame: .init(x: 0, y: 0, width: screen_Width, height: screen_Height), style: .plain)
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.estimatedRowHeight = 200
tableView.rowHeight = UITableView.automaticDimension
tableView.dataSource = self
tableView.delegate = self
tableView.register(MPPositive_PersonalisedRecommendationsTableViewCell.self, forCellReuseIdentifier: MPPositive_PersonalisedRecommendationsTableViewCellID)
tableView.register(MPPositive_HomeLibraryListstableViewCell.self, forCellReuseIdentifier: MPPositive_HomeLibraryListstableViewCellID)
tableView.register(MPPositive_HomeSinglesTableViewCell.self, forCellReuseIdentifier: MPPositive_HomeSinglesTableViewCellID)
tableView.register(MPPositive_HomeShowTableViewCell.self, forCellReuseIdentifier: MPPositive_HomeShowTableViewCellID)
tableView.contentInset = .init(top: 0, left: 0, bottom: 70*width, right: 0)
//
let footer = MJRefreshAutoGifFooter {
[weak self] in
self?.footerRefreshContinuationData()
}
footer.setTitle("Pull Up", for: .idle)
footer.setTitle("Release Refresh", for: .pulling)
footer.setTitle("Loading...", for: .refreshing)
footer.setTitle("No Data", for: .noMoreData)
tableView.mj_footer = footer
return tableView
}()
private let MPPositive_PersonalisedRecommendationsTableViewCellID = "MPPositive_PersonalisedRecommendationsTableViewCell"
private let MPPositive_HomeLibraryListstableViewCellID = "MPPositive_HomeLibraryListstableViewCell"
private let MPPositive_HomeSinglesTableViewCellID = "MPPositive_HomeSinglesTableViewCell"
private let MPPositive_HomeShowTableViewCellID = "MPPositive_HomeShowTableViewCell"
private var isFirstAppearance:Bool = true
//
private var personalModuleLists:[MPPositive_PersonalListViewModel] = []
//
private var browseModuleLists:[MPPositive_BrowseModuleListViewModel] = []
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
UMPConsentInformation.sharedInstance.requestConsentInfoUpdate(with: nil) { requestConsentError in
if let consentError = requestConsentError {
print("[UMP] GoogleUMP error=\(consentError.localizedDescription)")
return
}
print("[UMP] GoogleUMP success")
UMPConsentForm.loadAndPresentIfRequired(from: self) { loadAndPresentError in
if let consentError = loadAndPresentError {
print("[UMP] GoogleUMP error=\(consentError.localizedDescription)")
return
}
print("[UMP] GoogleUMP success")
}
}
}
MP_IAPManager.shared.systemRestorePurchases()
//API
MP_NetWorkManager.shared.requestYBMAPIKeyCode()
setTitle("")
confirgue()
if browseModuleLists.count == 0 {
MP_HUD.loading()
}
MP_AdMobManager.shared.configureLibraryNativeAd(rootController: self)
MP_AdMobManager.shared.loadLibraryNativeAd()
//广
MP_AdMobManager.shared.configureSreachNativeAd(rootController: self)
MP_AdMobManager.shared.loadSearchNativeAd()
errorBlock = {
[weak self] in
guard let self = self else {
return
}
//
guard browseModuleLists.count == 0 else {
MP_HUD.hideNow()
return
}
//
guard personalModuleLists.count == 0 else {
MP_HUD.hideNow()
return
}
//navView
view.subviews.forEach { item in
if item != self.topSafeAndNavView {
//
if item.superview != nil {
item.removeFromSuperview()
}
}
}
//View
setErrorView()
MP_HUD.hideNow()
}
retryBlock = {
[weak self] in
guard let self = self else {return}
MP_HUD.loading()
DispatchQueue.main.async {
//
MPPositive_BrowseLoadViewModel.shared.reloadBrowseLists()
}
}
//home
guard let last = UserDefaults.standard.object(forKey: "Last_Play_Songs") as? [String:Any] else {return}
guard let currentVideoId = last["currentVideoId"] as? String, let data = last["Songs"] as? Data, let array = jsonforCoreSongs(data) else {return}
//使Load
let lodaViewModel = MPPositive_PlayerLoadViewModel(array, currentVideoId: currentVideoId)
lodaViewModel.improveData(currentVideoId)
//
MP_PlayerManager.shared.setPlayType(.normal)
MP_PlayerManager.shared.setLastStatus(bool: true)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
}
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.notificationKey.add(observer: self, selector: #selector(reloadAction(_ :)), notificationName: .positive_browses_reload)
NotificationCenter.notificationKey.add(observer: self, selector: #selector(continuationDataCompletionEvent(_ :)), notificationName: .positive_browses_completion)
MPPositive_BrowseLoadViewModel.shared.libraryList.reloadLibrarys{
[weak self] in
guard let self = self else {return}
MPPositive_BrowseLoadViewModel.shared.getRecentlyData()
}
if isFirstAppearance == false {
//
presentGuide()
isFirstAppearance = true
}
MP_AnalyticsManager.shared.home_b_pvAction()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
//
private func createSearchView() -> UIView{
let searchView:UIView = UIView()
searchView.backgroundColor = .init(hex: "#212121")
searchView.isUserInteractionEnabled = true
searchView.layer.masksToBounds = true
searchView.layer.cornerRadius = 16*width
//icon
let iconImageView = UIImageView(image: .init(named: "Search_ICON'logo"))
searchView.addSubview(iconImageView)
iconImageView.snp.makeConstraints { make in
make.height.width.equalTo(16*width)
make.left.equalToSuperview().offset(16*width)
make.centerY.equalToSuperview()
}
let label = createLabel("Search songs,artists,playlists".localizableString(), font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .init(hex: "#666666"), textAlignment: .left)
searchView.addSubview(label)
label.snp.makeConstraints { make in
make.left.equalTo(iconImageView.snp.right).offset(8*width)
make.right.equalToSuperview().offset(-16*width)
make.centerY.equalToSuperview()
}
searchView.isUserInteractionEnabled = true
searchView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(searchClick(_:))))
return searchView
}
//
@objc fileprivate func searchClick(_ sender:UITapGestureRecognizer) {
isFirstAppearance = false
MP_AnalyticsManager.shared.search_from_actionAction("home page")
let resultVC = MPPositive_SearchResultShowViewController()
navigationController?.pushViewController(resultVC, animated: false)
}
///
func presentGuide() {
guard UserDefaults.standard.bool(forKey: "isGuide") != true else {
//
return
}
//2
guard var actives = UserDefaults.standard.object(forKey: "ActiveDays") as? [Date], actives.count >= 2 else {
return
}
//2
MPPositive_ModalType = .Guide
let guideVC = MP_GuideViewController()
guideVC.disMissBlock = {
DispatchQueue.main.async {
//
actives.removeAll()
let now = Date().timeZone()
UserDefaults.standard.setValue([now], forKey: "ActiveDays")
}
}
guideVC.feedBackBlock = {
DispatchQueue.main.async {
let alert = UIAlertController(title: "Feedback".localizableString(), message: "If you have any comments or suggestions, please contact us at the following e-mail address".localizableString(), preferredStyle: .actionSheet)
let email = UIAlertAction(title: "marketing@lux-ad.com", style: .default) { (_) in
//
UIPasteboard.general.string = "marketing@lux-ad.com"
MP_HUD.text("Successfully copied the e-mail address to the clipboard".localizableString(), delay: 1.0, completion: nil)
}
alert.addAction(email)
let cancel = UIAlertAction(title: "Cancel".localizableString(), style: .cancel)
alert.addAction(cancel)
self.present(alert, animated: true)
}
}
guideVC.storeBlock = {
DispatchQueue.main.async {
//AppStore
if let url = URL(string: "https://apps.apple.com/app/6502973957") {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}
guideVC.transitioningDelegate = self
guideVC.modalPresentationStyle = .custom
self.present(guideVC, animated: true)
}
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return MPPositive_PresentationController(presentedViewController: presented, presenting: presenting)
}
//
@objc private func footerRefreshContinuationData() {
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
tableView.mj_footer?.endRefreshing()
return
}
guard (MP_NetWorkManager.shared.continuationAndItct != nil) || (MPPositive_BrowseLoadViewModel.shared.browseModuleLists.isEmpty == true) else {
tableView.mj_footer?.endRefreshing()
return
}
MPPositive_BrowseLoadViewModel.shared.loadMoreBrowseDatas()
}
//
@objc private func continuationDataCompletionEvent(_ sender:Notification) {
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
tableView.mj_footer?.endRefreshingWithNoMoreData()
}
}
//MARK: - UI
//
private func confirgue() {
topSafeAndNavView.frame = .init(x: 0, y: 0, width: screen_Width, height: navAndstatusBarHeight + 40*width)
navView.snp.updateConstraints { make in
make.height.equalTo(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)
}
}
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)
}
}
if HiMelodyLabel.superview == nil {
navView.addSubview(HiMelodyLabel)
HiMelodyLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16*width)
make.centerY.equalTo(memuBtn)
}
HiMelodyLabel.setGradientTextColor(gradientTextColors)
}
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: -
//
@objc private func reloadAction(_ sender:Notification?) {
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
if tableView.superview == nil {
confirgue()
}
removeErrorView()
MP_HUD.hideNow()
personalModuleLists = MPPositive_BrowseLoadViewModel.shared.personalModuleLists
browseModuleLists = MPPositive_BrowseLoadViewModel.shared.browseModuleLists
tableView.showMessage((browseModuleLists.count == 0 && personalModuleLists.count == 0) ? 0:1)
//
tableView.reloadData()
tableView.mj_footer?.endRefreshing()
}
}
//MARK: -
//
@objc private func menuRightClick(_ sender:UIButton) {
isFirstAppearance = false
let setVC = MPSideA_SettingViewController()
setVC.cleanSide = true
navigationController?.pushViewController(setVC, animated: true)
}
//VIP
@objc private func vipIAPClick(_ sender:UITapGestureRecognizer) {
view.endEditing(true)
MP_AnalyticsManager.shared.VIP_clickAction()
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)
}
@objc private func scrollTopAction(_ sender:UITapGestureRecognizer) {
let topOffset = CGPoint(x: 0, y: 0)
tableView.setContentOffset(topOffset, animated: true)
}
}
//MARK: - tableView
extension MPPositive_HomeViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
//tableView
if personalModuleLists.isEmpty && MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels.isEmpty {
//
return 1
}else {
//
return 2
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if personalModuleLists.isEmpty && MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels.isEmpty {
//
return browseModuleLists.count
}else {
//,
if MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels.isEmpty {
switch section {
case 0:
//
return personalModuleLists.count
default:
return browseModuleLists.count
}
}else {
switch section {
case 0:
//LibraryLibrary
return personalModuleLists.count + 1
default:
return browseModuleLists.count
}
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if personalModuleLists.isEmpty && MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels.isEmpty {
//
let row = indexPath.row
return setHomeYoutubeLayoutCell(tableView, row: row, indexPath: indexPath)
}else {
switch indexPath.section {
case 0://
//,
if MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels.isEmpty {
let row:Int = indexPath.row
//
return setHomePersonlLayoutCell(tableView, row: row)
}else {
//LibraryLibrary
if personalModuleLists.isEmpty {
//library
return setLibraryCell(tableView, indexPath: indexPath)
}else {
//
let row:Int = indexPath.row == 0 ? 0:(indexPath.row-1)
if indexPath.row == 1 {
//library
return setLibraryCell(tableView, indexPath: indexPath)
}else {
//
return setHomePersonlLayoutCell(tableView, row: row)
}
}
}
default://
let row = indexPath.row
return setHomeYoutubeLayoutCell(tableView, row: row, indexPath: indexPath)
}
}
}
//Cell
private func setHomePersonlLayoutCell(_ tableView:UITableView, row:Int) -> UITableViewCell {
switch row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeSinglesTableViewCellID) as! MPPositive_HomeSinglesTableViewCell
cell.personlViewModel = personalModuleLists[row]
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_PersonalisedRecommendationsTableViewCellID) as! MPPositive_PersonalisedRecommendationsTableViewCell
cell.personlViewModel = personalModuleLists[row]
cell.reloadRecommondBlock = {
[weak self] index in
switch index {
case 1://
let array = MPPositive_LoadCoreModel.shared.recents
MPPositive_BrowseLoadViewModel.shared.getRecommondFirstNumberData(array) { [weak self] personl in
guard let self = self, let item = personl else {
DispatchQueue.main.async {
self?.tableView.reloadSections(.init(integer: 0), with: .automatic)
}
return
}
//
if MPPositive_BrowseLoadViewModel.shared.personalModuleLists.indices.contains(index) {
//
MPPositive_BrowseLoadViewModel.shared.personalModuleLists[index] = item
}else {
//
MPPositive_BrowseLoadViewModel.shared.personalModuleLists.insert(item, at: 1)
}
self.personalModuleLists = MPPositive_BrowseLoadViewModel.shared.personalModuleLists
DispatchQueue.main.async {
self.tableView.reloadSections(.init(integer: 0), with: .automatic)
}
}
default://
let array = MPPositive_LoadCoreModel.shared.recents
MPPositive_BrowseLoadViewModel.shared.getRecommondSecondNumberData(array) { [weak self] personl in
guard let self = self, let item = personl else {
DispatchQueue.main.async {
self?.tableView.reloadSections(.init(integer: 0), with: .automatic)
}
return
}
//
if MPPositive_BrowseLoadViewModel.shared.personalModuleLists.indices.contains(index) {
//
MPPositive_BrowseLoadViewModel.shared.personalModuleLists[index] = item
}else {
//
MPPositive_BrowseLoadViewModel.shared.personalModuleLists.append(item)
}
self.personalModuleLists = MPPositive_BrowseLoadViewModel.shared.personalModuleLists
DispatchQueue.main.async {
self.tableView.reloadSections(.init(integer: 0), with: .automatic)
}
}
}
}
return cell
}
}
//Cell
private func setHomeYoutubeLayoutCell(_ tableView:UITableView, row:Int, indexPath:IndexPath) -> UITableViewCell {
if let first = browseModuleLists[row].items.first, first.browseItem.itemType == .single, (first.browseItem.pageType == "MUSIC_VIDEO_TYPE_ATV" || first.browseItem.pageType == "MUSIC_VIDEO_TYPE_UGC") {
//
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeSinglesTableViewCellID, for: indexPath) as! MPPositive_HomeSinglesTableViewCell
cell.browseViewModel = browseModuleLists[row]
return cell
}else {
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeShowTableViewCellID, for: indexPath) as! MPPositive_HomeShowTableViewCell
cell.browseViewModel = browseModuleLists[row]
cell.requestNextBlock = {
[weak self] (item) in
guard let self = self else {return}
requestNextEvent(item)
}
cell.findMoreBlock = {
[weak self] in
guard let self = self else {return}
isFirstAppearance = false
let moreVC = MPPositive_MoreContentViewController(browseModuleLists[row])
navigationController?.pushViewController(moreVC, animated: true)
}
return cell
}
}
//LibraryCell
private func setLibraryCell(_ tableView:UITableView, indexPath:IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeLibraryListstableViewCellID, for: indexPath) as! MPPositive_HomeLibraryListstableViewCell
cell.libraryViewModels = MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels
return cell
}
////
private func requestNextEvent(_ item:MPPositive_BrowseItemViewModel){
MP_AnalyticsManager.shared.home_b_module_clickAction(item.browseItem.pageType ?? "")
switch item.browseItem.itemType {
case .single:
///
MPPositive_Debouncer.shared.call {
[weak self] in
guard let self = self else {return}
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
playOfflineSongs(item.browseItem.videoId ?? "")
return
}
MP_AnalyticsManager.shared.song_clickAction("Home")
//
MP_PlayerManager.shared.loadPlayer = nil
//
NotificationCenter.notificationKey.post(notificationName: .pup_player_vc)
MP_AnalyticsManager.shared.player_b_impAction()
//next
MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams){ [weak self] listSongs in
guard let self = self else {return}
//playerloadViewModel
let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.browseItem.videoId ?? "")
lodaViewModel.improveData(item.browseItem.videoId ?? "")
//
MP_PlayerManager.shared.setPlayType(.normal)
MP_PlayerManager.shared.loadPlayer = lodaViewModel
MP_AnalyticsManager.shared.player_b_listAction()
}
}
case .list:
isFirstAppearance = false
//
let listVC = MPPositive_ListShowViewController(item.browseItem.browseId ?? "", params: "", title: item.title ?? "", subtitle: item.subtitle ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "")
navigationController?.pushViewController(listVC, animated: true)
case .artist:
isFirstAppearance = false
//
let artistVC = MPPositive_ArtistShowViewController(item.browseItem.artistId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "")
navigationController?.pushViewController(artistVC, animated: true)
default:
break
}
}
}