PQStuckPointMusicController.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. //
  2. // PQStuckPointMusicController.swift
  3. // PQSpeed
  4. //
  5. // Created by SanW on 2021/4/28.
  6. // Copyright © 2021 BytesFlow. All rights reserved.
  7. //
  8. import UIKit
  9. import AVFoundation
  10. class PQStuckPointMusicController: PQBaseViewController {
  11. // 选中的总时长
  12. var selectedTotalDuration: Float64 = 0
  13. // 选择的总数
  14. var selectedDataCount: Int = 0
  15. // 选择的图片总数
  16. var selectedImageDataCount: Int = 0
  17. // 选中的素材数据
  18. var selectedPhotoData: [PQEditVisionTrackMaterialsModel]?
  19. // 选中的音乐数据
  20. var selectedMusicData: PQVoiceModel?
  21. /// 缓存数据
  22. /// ["tagId":
  23. /// [
  24. /// "tagInfo":([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat)),
  25. /// "pageList":[PQVoiceModel],
  26. /// "currentTag": PQStuckPointMusicTagsModel
  27. /// ]
  28. /// ]
  29. var cacheMusicData: [String: [String: Any]] = Dictionary<String, [String: Any]>.init()
  30. // 热搜数据
  31. var hotList: [Any] = Array<Any>.init()
  32. // 左边距离
  33. let leftMargin: CGFloat = 16
  34. // 搜索拦高度
  35. let searchTFH: CGFloat = 37
  36. // 当前页码
  37. var pageNum: Int = 0
  38. // 当前标签信息-如果是热门则为空
  39. var tagData: PQStuckPointMusicTagsModel?
  40. // 当前播放的音乐
  41. var currentPlayData: PQVoiceModel?
  42. // 当前播放的视频
  43. var playerItem: AVPlayerItem?
  44. lazy var avPlayer: AVPlayer = {
  45. let avPlayer = AVPlayer()
  46. PQNotification.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: avPlayer.currentItem, queue: .main) { [weak self] notify in
  47. BFLog(message: "AVPlayerItemDidPlayToEndTime = \(notify)")
  48. avPlayer.seek(to: CMTime(value: CMTimeValue((self?.currentPlayData?.startTime ?? 0) * 1000), timescale: CMTimeScale(playerTimescale)))
  49. // avPlayer.play()
  50. self?.playStuckPointMusic(itemData: nil)
  51. }
  52. PQNotification.addObserver(forName: .AVPlayerItemNewErrorLogEntry, object: avPlayer.currentItem, queue: .main) { notify in
  53. BFLog(message: "AVPlayerItemNewErrorLogEntry = \(notify)")
  54. }
  55. PQNotification.addObserver(forName: .AVPlayerItemFailedToPlayToEndTime, object: avPlayer.currentItem, queue: .main) { notify in
  56. BFLog(message: "AVPlayerItemFailedToPlayToEndTime = \(notify)")
  57. }
  58. PQNotification.addObserver(forName: .AVPlayerItemPlaybackStalled, object: avPlayer.currentItem, queue: .main) { notify in
  59. BFLog(message: "AVPlayerItemPlaybackStalled = \(notify)")
  60. }
  61. avPlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: CMTimeScale(playerTimescale)), queue: .main) { [weak self] cmTime in
  62. BFLog(message: "addPeriodicTimeObserver = \(cmTime)")
  63. }
  64. return avPlayer
  65. }()
  66. // 输入框清空按钮
  67. lazy var clearBtn: UIButton = {
  68. let clearBtn = UIButton(type: .custom)
  69. clearBtn.setImage(UIImage.init().BF_Image(named: "icon_search_delete"), for: .normal)
  70. clearBtn.frame = CGRect(x: 0, y: 0, width: 28, height: 32)
  71. clearBtn.tag = 1
  72. clearBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
  73. clearBtn.isHidden = true
  74. return clearBtn
  75. }()
  76. // 搜索框
  77. lazy var searchTF: UITextField = {
  78. let searchTF = UITextField(frame: CGRect(x: leftMargin, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth - leftMargin * 2, height: searchTFH))
  79. searchTF.font = UIFont.systemFont(ofSize: 17)
  80. searchTF.backgroundColor = UIColor.hexColor(hexadecimal: "#F2F2F2")
  81. searchTF.attributedPlaceholder = NSAttributedString(string: "搜索歌曲名称/歌手", attributes: [.foregroundColor: UIColor.hexColor(hexadecimal: "#BDBDBD"), .font: UIFont.systemFont(ofSize: 14)])
  82. searchTF.textColor = PQBFConfig.shared.styleTitleColor
  83. searchTF.addCorner(corner: searchTFH / 2)
  84. searchTF.leftViewMode = .always
  85. let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 35, height: 32))
  86. let imageView = UIImageView(image: UIImage.init().BF_Image(named: "icon_search_s"))
  87. imageView.frame = CGRect(x: 15, y: 8, width: 16, height: 16)
  88. leftView.addSubview(imageView)
  89. searchTF.leftView = leftView
  90. searchTF.delegate = self
  91. searchTF.rightViewMode = .always
  92. let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 32))
  93. rightView.addSubview(clearBtn)
  94. searchTF.rightView = rightView
  95. searchTF.delegate = self
  96. searchTF.returnKeyType = .search
  97. searchTF.addTarget(self, action: #selector(editingChanged), for: .editingChanged)
  98. return searchTF
  99. }()
  100. /// 一级分类视图
  101. lazy var topCategoryController: PQStuckPointMusicContentController = {
  102. let topCategoryController = PQStuckPointMusicContentController()
  103. addChild(topCategoryController)
  104. view.addSubview(topCategoryController.view)
  105. topCategoryController.updateViewFrame(newFrame: CGRect(x: 0, y: searchTF.frame.maxY + cDefaultMargin * 2, width: cDefaultMargin * 12, height: view.frame.height - (searchTF.frame.maxY + cDefaultMargin * 2)))
  106. // 一级分类点击
  107. topCategoryController.didSelectedHandle = { [weak self] _, _, _, itemData in
  108. if itemData is PQStuckPointMusicTagsModel {
  109. self?.tagData = itemData as? PQStuckPointMusicTagsModel
  110. self?.dealWithCategorySelectedData(itemData: itemData as? PQStuckPointMusicTagsModel)
  111. // 更新当前标签
  112. self?.updateMusicCacheData(tagId: (itemData as? PQStuckPointMusicTagsModel)?.tagId ?? 0, tagInfo: nil, pageList: nil, currentTag: self?.tagData)
  113. }
  114. self?.playStuckPointMusic(itemData: nil, isClearCurrentMusic: true)
  115. }
  116. return topCategoryController
  117. }()
  118. /// 音乐列表视图
  119. lazy var musicPageController: PQStuckPointMusicContentController = {
  120. let musicPageController = PQStuckPointMusicContentController()
  121. musicPageController.cellHight = cDefaultMargin * 8
  122. addChild(musicPageController)
  123. view.addSubview(musicPageController.view)
  124. musicPageController.updateViewFrame(newFrame: CGRect(x: topCategoryController.view.frame.maxX, y: topCategoryController.view.frame.minY, width: view.frame.width - topCategoryController.view.frame.maxX, height: topCategoryController.view.frame.height))
  125. musicPageController.contentType = .page
  126. musicPageController.didSelectedHandle = { [weak self] isTagsClick, _, _, itemData in
  127. if isTagsClick { // 二级分类点击
  128. self?.tagData = (itemData as? PQStuckPointMusicTagsModel)
  129. let tagId: Int64 = (itemData as? PQStuckPointMusicTagsModel)?.tagId ?? 0
  130. let parentTagId: Int64 = (itemData as? PQStuckPointMusicTagsModel)?.parentTagId ?? 0
  131. // 请求列表数据
  132. self?.requestPageListData(tagId: tagId, parentTagId: parentTagId)
  133. } else {
  134. self?.playStuckPointMusic(itemData: itemData as? PQVoiceModel)
  135. }
  136. }
  137. musicPageController.refreshHandle = { [weak self] isRefresh, _ in
  138. let tagId: Int64 = self?.tagData?.tagId ?? 0
  139. let parentTagId: Int64 = self?.tagData?.parentTagId ?? 0
  140. // self?.musicPageController.tagsInfo = (tags, tagAttributes) as? ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat))
  141. // 请求列表数据
  142. self?.requestPageListData(isRefresh: isRefresh, tagId: tagId, parentTagId: parentTagId)
  143. // 请求二级标签数据
  144. // self?.loadRequestSubTagsList()
  145. self?.playStuckPointMusic(itemData: nil, isClearCurrentMusic: true)
  146. }
  147. musicPageController.btnClickHandle = { [weak self] _, bgmData in
  148. // 使用音乐
  149. self?.userstuckPointMusic(musicData: bgmData as? PQVoiceModel)
  150. }
  151. return musicPageController
  152. }()
  153. /// 搜索控制器
  154. lazy var searchController: PQStuckPointMusicSearchController = {
  155. let searchController = PQStuckPointMusicSearchController()
  156. searchController.selectedDataCount = selectedDataCount
  157. searchController.selectedImageDataCount = selectedImageDataCount
  158. searchController.selectedTotalDuration = selectedTotalDuration
  159. searchController.cellHight = cDefaultMargin * 8
  160. addChild(searchController)
  161. view.addSubview(searchController.view)
  162. searchController.updateViewFrame(newFrame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei + cDefaultMargin * 2, width: view.frame.width, height: view.frame.height - (cDevice_iPhoneNavBarAndStatusBarHei + cDefaultMargin * 2)))
  163. searchController.didSelectedHandle = { [weak self] isTagsClick, _, _, itemData in
  164. if !isTagsClick {
  165. self?.view.endEditing(true)
  166. if !(itemData is PQEmptyModel) {
  167. self?.playStuckPointMusic(itemData: itemData as? PQVoiceModel)
  168. }
  169. }
  170. }
  171. searchController.btnClickHandle = { [weak self] _, bgmData in
  172. // 使用音乐
  173. self?.userstuckPointMusic(musicData: bgmData as? PQVoiceModel)
  174. }
  175. searchController.scroDidScroHandle = { [weak self] in
  176. self?.view.endEditing(true)
  177. }
  178. searchController.view.isHidden = true
  179. searchController.contentType = .serach
  180. return searchController
  181. }()
  182. lazy var emptyRemindView: PQEmptyRemindView = {
  183. let emptyRemindView = PQEmptyRemindView(frame: CGRect(x: 0, y: searchTF.frame.maxY + cDefaultMargin * 2, width: view.frame.width, height: view.frame.height - (searchTF.frame.maxY + cDefaultMargin * 2)))
  184. emptyRemindView.remindLab.font = UIFont.systemFont(ofSize: 20)
  185. emptyRemindView.remindLab.textColor = UIColor.hexColor(hexadecimal: "#575757")
  186. emptyRemindView.isHidden = true
  187. let emptyData = PQEmptyModel()
  188. emptyData.title = "暂无音乐"
  189. emptyRemindView.emptyData = emptyData
  190. emptyRemindView.fullRefreshBloc = { [weak self] _, _ in
  191. /// 请求标签数据
  192. self?.loadRequestTagsList()
  193. }
  194. view.addSubview(emptyRemindView)
  195. return emptyRemindView
  196. }()
  197. /// 已选择音乐view
  198. lazy var selectedMusciView: PQStuckPointMusicContentCell = {
  199. let selectedMusciView = PQStuckPointMusicContentCell(frame: CGRect(x: 0, y: view.frame.height - cDefaultMargin * 6, width: cScreenWidth, height: cDefaultMargin * 6))
  200. selectedMusciView.confirmContentView.backgroundColor = UIColor.hexColor(hexadecimal: "#333333")
  201. selectedMusciView.playImageView.isHidden = true
  202. selectedMusciView.confirmBtn.setTitle(" 继续使用 ", for: .normal)
  203. selectedMusciView.backgroundColor = UIColor.hexColor(hexadecimal: "#333333")
  204. view.addSubview(selectedMusciView)
  205. return selectedMusciView
  206. }()
  207. override func viewDidLoad() {
  208. super.viewDidLoad()
  209. leftButton(image: "icon_detail_back",tintColor: PQBFConfig.shared.styleTitleColor)
  210. setTitle(title: "选择音乐主题",color: PQBFConfig.shared.styleTitleColor)
  211. view.addSubview(searchTF)
  212. addKeyboardObserver()
  213. /// 请求标签数据
  214. loadRequestTagsList()
  215. PQNotification.addObserver(self, selector: #selector(enterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
  216. if selectedMusicData != nil {
  217. let editerVC: PQStuckPointEditerController = PQStuckPointEditerController()
  218. editerVC.stuckPointMusicData = selectedMusicData
  219. editerVC.selectedDataCount = selectedDataCount
  220. editerVC.selectedImageDataCount = selectedImageDataCount
  221. editerVC.selectedTotalDuration = selectedTotalDuration
  222. editerVC.selectedPhotoData = selectedPhotoData
  223. navigationController?.pushViewController(editerVC, animated: true)
  224. }
  225. // 卡点视频音乐选择曝光上报
  226. PQEventTrackViewModel.baseReportUpload(businessType: .bt_windowView, objectType: .ot_view_selectSyncedUpMusic, pageSource: .sp_stuck_selectSynceedUpMusic, extParams: nil, remindmsg: "卡点视频数据上报-(曝光上报:卡点视频音乐选择页)")
  227. }
  228. override func viewWillDisappear(_ animated: Bool) {
  229. super.viewWillDisappear(animated)
  230. playStuckPointMusic(itemData: nil)
  231. }
  232. /// 按钮点击事件
  233. /// - Parameter sender: <#sender description#>
  234. /// - Returns: <#description#>
  235. @objc func btnClick(sender: UIButton) {
  236. switch sender.tag {
  237. case 1: // 清除
  238. searchTF.text = nil
  239. // emptyRemindView.isHidden = true
  240. clearBtn.isHidden = true
  241. default:
  242. break
  243. }
  244. }
  245. /// 请求标签数据
  246. /// - Returns: <#description#>
  247. func loadRequestTagsList() {
  248. PQLoadingHUB.shared.showHUB()
  249. PQStuckPointViewModel.stuckPointMusicCategoryList { [weak self] tags, _, _ in
  250. PQLoadingHUB.shared.dismissHUB()
  251. if tags.count > 0 {
  252. self?.tagData = tags.first
  253. }
  254. self?.emptyRemindView.isHidden = tags.count > 0
  255. if tags.count > 0 {
  256. self?.topCategoryController.configMusicListData(isRefresh: true, musicListData: tags)
  257. // 请求列表数据
  258. self?.requestPageListData(isHotPage: true, tagId: tags.first?.tagId ?? 0, parentTagId: 0)
  259. }
  260. }
  261. }
  262. /// 请求二级标签数据
  263. /// - Returns: <#description#>
  264. func loadRequestSubTagsList() {
  265. PQLoadingHUB.shared.showHUB()
  266. PQStuckPointViewModel.stuckPointMusicCategoryList(parentTagId: tagData?.tagId ?? 0) { [weak self] tags, _, tagAttributes in
  267. PQLoadingHUB.shared.dismissHUB()
  268. if tagAttributes != nil {
  269. let tagId: Int64 = tags.count > 0 ? (tags.first?.tagId ?? 0) : (self?.tagData?.tagId ?? 0)
  270. let parentTagId: Int64 = tags.count > 0 ? (self?.tagData?.tagId ?? 0) : 0
  271. self?.musicPageController.tagsInfo = (tags, tagAttributes) as? ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat))
  272. if tags.count > 0 {
  273. self?.tagData = tags.first
  274. }
  275. // 添加缓存
  276. self?.updateMusicCacheData(tagId: parentTagId > 0 ? parentTagId : tagId, isClearOld: false, tagInfo: self?.musicPageController.tagsInfo, pageList: nil, currentTag: self?.tagData)
  277. // 请求列表数据
  278. self?.requestPageListData(tagId: tagId, parentTagId: parentTagId)
  279. } else {
  280. // 重置数据
  281. self?.resetPageData(isResetData: false)
  282. }
  283. }
  284. }
  285. /// 处理cell点击回调
  286. /// - Parameter itemData: <#itemData description#>
  287. /// - Returns: <#description#>
  288. func dealWithCategorySelectedData(itemData: PQStuckPointMusicTagsModel?) {
  289. tagData = itemData
  290. // 重置数据
  291. resetPageData(isResetData: true)
  292. let cacheData = getMusicCacheData(itemData: itemData)
  293. if cacheData != nil, (cacheData?.0 != nil && (cacheData?.0?.0.count ?? 0) > 0) || (cacheData?.1 != nil && (cacheData?.1?.count ?? 0) > 0) {
  294. musicPageController.tagsInfo = cacheData?.0
  295. musicPageController.configMusicListData(isRefresh: true, musicListData: cacheData?.1 ?? [])
  296. pageNum = ((cacheData?.1?.count ?? 0) / 20) + 1
  297. tagData = cacheData?.2
  298. } else {
  299. pageNum = 1
  300. // 请求二级标签数据
  301. loadRequestSubTagsList()
  302. }
  303. }
  304. /// 请求列表数据
  305. /// - Parameters:
  306. /// - tagId: <#tagId description#>
  307. /// - parentTagId: <#parentTagId description#>
  308. /// - tagsInfo: <#tagsInfo description#>
  309. /// - Returns: <#description#>
  310. func requestPageListData(isRefresh: Bool = true, isHotPage: Bool = false, tagId: Int64, parentTagId: Int64) {
  311. PQLoadingHUB.shared.showHUB()
  312. if isRefresh {
  313. pageNum = 1
  314. }
  315. PQStuckPointViewModel.stuckPointMusicPageList(tagId: tagId, parentTagId: parentTagId, pageNum: pageNum,videoCount: selectedDataCount - selectedImageDataCount,imageCount: selectedImageDataCount,totalDuration: selectedTotalDuration) { [weak self] musicInfo, _ in
  316. PQLoadingHUB.shared.dismissHUB()
  317. if musicInfo.count > 0 {
  318. self?.pageNum = (self?.pageNum ?? 0) + 1
  319. }
  320. self?.musicPageController.configMusicListData(isRefresh: isRefresh, musicListData: musicInfo)
  321. // 添加缓存
  322. self?.updateMusicCacheData(tagId: parentTagId > 0 ? parentTagId : tagId, isClearOld: isRefresh, tagInfo: nil, pageList: musicInfo, currentTag: nil)
  323. if musicInfo.count > 0, isHotPage, isRefresh {
  324. self?.hotList = musicInfo
  325. self?.searchController.hotList = self?.hotList ?? []
  326. }
  327. }
  328. }
  329. /// 重置页面数据
  330. /// - Parameter isResetData: <#isResetData description#>
  331. /// - Returns: <#description#>
  332. func resetPageData(isResetData: Bool) {
  333. musicPageController.tagsInfo = nil
  334. musicPageController.configMusicListData(isResetData: isResetData, isRefresh: true, musicListData: [])
  335. pageNum = 1
  336. }
  337. /// 播放音乐
  338. /// - Parameter itemData: <#itemData description#>
  339. func playStuckPointMusic(itemData: PQVoiceModel?, isClearCurrentMusic: Bool = false) {
  340. if itemData != nil, currentPlayData != itemData {
  341. if !isValidURL(url: itemData?.musicPath ?? "") {
  342. cShowHUB(superView: nil, msg: "本歌曲暂无伴奏版本哦~")
  343. return
  344. }
  345. avPlayer.pause()
  346. playerItem?.removeObserver(self, forKeyPath: "status")
  347. playerItem?.removeObserver(self, forKeyPath: "error")
  348. playerItem = AVPlayerItem(url: URL(string: itemData?.musicPath ?? "")!)
  349. if (itemData?.endTime ?? 0) > 0, (itemData?.endTime ?? 0) > (itemData?.startTime ?? 0) {
  350. playerItem?.forwardPlaybackEndTime = CMTime(value: CMTimeValue((itemData?.endTime ?? 0) * playerTimescale), timescale: CMTimeScale(playerTimescale))
  351. }
  352. avPlayer.replaceCurrentItem(with: playerItem)
  353. playerItem?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
  354. playerItem?.addObserver(self, forKeyPath: "error", options: .new, context: nil)
  355. avPlayer.seek(to: CMTime(value: CMTimeValue((itemData?.startTime ?? 0) * playerTimescale), timescale: CMTimeScale(playerTimescale)))
  356. avPlayer.play()
  357. // let player = TXVodPlayer()
  358. // let config = TXVodPlayConfig()
  359. // config.cacheFolderPath = videoCacheDirectory
  360. // config.maxCacheItems = 0
  361. // player.config = config
  362. //// player.vodDelegate = self
  363. // player.setRenderMode(.RENDER_MODE_FILL_EDGE)
  364. // player.startPlay("https://clipres.yishihui.com/longvideo/material/voice/prod/20210512/MUSIC_QQ_000T1Ws32MWrUj")
  365. currentPlayData = itemData
  366. } else if itemData != nil, avPlayer.rate == 0.0 {
  367. avPlayer.play()
  368. } else {
  369. avPlayer.pause()
  370. musicPageController.updateCurrentPlayMusic(isPlaying: false, isClearCurrentMusic: isClearCurrentMusic)
  371. searchController.updateCurrentPlayMusic(isPlaying: false, isClearCurrentMusic: isClearCurrentMusic)
  372. }
  373. if isClearCurrentMusic {
  374. avPlayer.pause()
  375. currentPlayData = nil
  376. }
  377. }
  378. /// 使用卡点音乐
  379. /// - Parameter musicData: <#musicData description#>
  380. /// - Returns: <#description#>
  381. func userstuckPointMusic(musicData: PQVoiceModel?) {
  382. if musicData != nil {
  383. let editerVC: PQStuckPointEditerController = PQStuckPointEditerController()
  384. editerVC.selectedDataCount = selectedDataCount
  385. editerVC.selectedImageDataCount = selectedImageDataCount
  386. editerVC.selectedTotalDuration = selectedTotalDuration
  387. editerVC.stuckPointMusicData = musicData
  388. editerVC.selectedPhotoData = selectedPhotoData
  389. navigationController?.pushViewController(editerVC, animated: true)
  390. }
  391. }
  392. /// 返回按钮操作
  393. override func backBtnClick() {
  394. if searchController.view.isHidden {
  395. navigationController?.popViewController(animated: true)
  396. // 点击上报:选择音乐分类
  397. PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_back, pageSource: .sp_stuck_selectSynceedUpMusic, extParams: nil, remindmsg: "卡点视频数据上报-(点击上报:返回按钮)")
  398. } else {
  399. hiddenSearchController()
  400. // 点击上报:返回按钮
  401. PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_back, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: nil, remindmsg: "卡点视频数据上报-(点击上报:返回按钮)")
  402. }
  403. }
  404. /// 进入后台暂停播放
  405. @objc func enterBackground() {
  406. playStuckPointMusic(itemData: nil)
  407. }
  408. deinit {
  409. PQNotification.removeObserver(self)
  410. avPlayer.currentItem?.removeObserver(self, forKeyPath: "status")
  411. avPlayer.currentItem?.removeObserver(self, forKeyPath: "error")
  412. avPlayer.pause()
  413. avPlayer.replaceCurrentItem(with: nil)
  414. playerItem = nil
  415. }
  416. }
  417. // MARK: - 音乐搜索相关
  418. /// 音乐搜索相关
  419. extension PQStuckPointMusicController: UITextFieldDelegate {
  420. /// 点击输入框
  421. @objc func editingChanged() {
  422. if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0, searchTF.markedTextRange == nil {
  423. if searchTF.text?.isSpace ?? false {
  424. return
  425. }
  426. // loadSearchData()
  427. clearBtn.isHidden = false
  428. }
  429. }
  430. /// 搜索
  431. @objc func loadSearchData() {
  432. if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0, searchTF.text?.isSpace ?? false {
  433. cShowHUB(superView: nil, msg: "搜索内容不能为空")
  434. return
  435. }
  436. if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0 {
  437. BFLog(message: "背景音乐--开始搜索背景音乐-1")
  438. searchController.loadSearchData(keyword: searchTF.text)
  439. }
  440. }
  441. /// 添加键盘监听
  442. /// - Returns: <#description#>
  443. func addKeyboardObserver() {
  444. // 监听键盘的显示和隐藏
  445. PQNotification.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
  446. PQNotification.addObserver(self, selector: #selector(keyboardWillHidden), name: UIResponder.keyboardWillHideNotification, object: nil)
  447. }
  448. /// 键盘显示
  449. /// - Parameter notification: <#notification description#>
  450. @objc func keyboardWillShow(notification: Notification) {
  451. let duration: TimeInterval = TimeInterval("\(notification.userInfo?["UIKeyboardAnimationDurationUserInfoKey"] ?? "1")") ?? 1
  452. UIView.animate(withDuration: duration) { [weak self] in
  453. self?.navTitleLabel?.alpha = 0
  454. self?.searchTF.frame = CGRect(x: cDefaultMargin * 5, y: (cDevice_iPhoneNavBarHei - (self?.searchTFH ?? 37.0)) / 2 + cDevice_iPhoneStatusBarHei, width: cScreenWidth - cDefaultMargin * 7, height: self?.searchTFH ?? 37.0)
  455. } completion: { _ in
  456. }
  457. searchController.view.isHidden = false
  458. hotList.forEach { item in
  459. if item is PQVoiceModel {
  460. (item as? PQVoiceModel)?.isSelected = false
  461. (item as? PQVoiceModel)?.isPlaying = false
  462. }
  463. }
  464. musicPageController.collectionView.reloadData()
  465. searchController.hotList = hotList
  466. playStuckPointMusic(itemData: nil)
  467. // 曝光上报:音乐素材搜索页
  468. PQEventTrackViewModel.baseReportUpload(businessType: .bt_windowView, objectType: .ot_view_searchSyncedUpMusic, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: nil, remindmsg: "卡点视频数据上报-(曝光上报:音乐素材搜索页)")
  469. }
  470. /// 键盘将要隐藏
  471. @objc func keyboardWillHidden() {}
  472. /// 隐藏搜索界面
  473. /// - Returns: <#description#>
  474. func hiddenSearchController() {
  475. view.endEditing(true)
  476. UIView.animate(withDuration: 0.3) { [weak self] in
  477. self?.navTitleLabel?.alpha = 1
  478. self?.searchTF.frame = CGRect(x: self?.leftMargin ?? 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth - (self?.leftMargin ?? 0) * 2, height: self?.searchTFH ?? 0)
  479. } completion: { _ in
  480. }
  481. clearBtn.isHidden = true
  482. searchController.view.isHidden = true
  483. // searchTF.text = nil
  484. // searchController.clearData()
  485. // currentPlayData?.isSelected = false
  486. // currentPlayData?.isPlaying = false
  487. playStuckPointMusic(itemData: nil)
  488. }
  489. override func touchesBegan(_: Set<UITouch>, with _: UIEvent?) {
  490. view.endEditing(true)
  491. }
  492. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  493. loadSearchData()
  494. view.endEditing(true)
  495. if textField.text == nil || (textField.text?.count ?? 0) <= 0 {
  496. cShowHUB(superView: nil, msg: "请先输入搜索内容")
  497. }
  498. return true
  499. }
  500. }
  501. // MARK: - 缓存相关
  502. /// 缓存相关
  503. extension PQStuckPointMusicController {
  504. /// 获取缓存数据
  505. /// - Parameter itemData: <#itemData description#>
  506. /// - Returns: <#description#>
  507. func getMusicCacheData(itemData: PQStuckPointMusicTagsModel?) -> (([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat))?, [PQVoiceModel]?, PQStuckPointMusicTagsModel?)? {
  508. if itemData != nil, cacheMusicData.keys.contains("\(itemData?.tagId ?? 0)") {
  509. let tempData = cacheMusicData["\(itemData?.tagId ?? 0)"]
  510. return (tempData?["tagInfo"] as? ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat)), tempData?["pageList"] as? [PQVoiceModel], tempData?["currentTag"] as? PQStuckPointMusicTagsModel)
  511. } else {
  512. return nil
  513. }
  514. }
  515. /// 更新缓存
  516. /// - Parameters:
  517. /// - tagId: 一级分类id
  518. /// - isClearOld: 是否清空老数据
  519. /// - tagInfo: 二级标签信息
  520. /// - pageList: 音乐数据
  521. /// - currentTag: 当前页当前标签
  522. /// - Returns: <#description#>
  523. func updateMusicCacheData(tagId: Int64, isClearOld: Bool = false, tagInfo: ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat))?, pageList: [PQVoiceModel]?, currentTag: PQStuckPointMusicTagsModel?) {
  524. if (tagInfo != nil && (tagInfo?.0.count ?? 0) > 0) || (pageList != nil && (pageList?.count ?? 0) > 0) || currentTag != nil {
  525. if cacheMusicData.keys.contains("\(tagId)") {
  526. var tempDic = cacheMusicData["\(tagId)"]
  527. if tagInfo != nil, (tagInfo?.0.count ?? 0) > 0 {
  528. tempDic?["tagInfo"] = tagInfo!
  529. }
  530. if pageList != nil, (pageList?.count ?? 0) > 0 {
  531. var oldPageList: [PQVoiceModel] = (tempDic?["pageList"] as? [PQVoiceModel]) ?? Array<PQVoiceModel>.init()
  532. if isClearOld {
  533. oldPageList.removeAll()
  534. }
  535. if oldPageList.count > 0 {
  536. tempDic?["pageList"] = oldPageList + pageList!
  537. } else {
  538. tempDic?["pageList"] = pageList!
  539. }
  540. }
  541. if currentTag != nil {
  542. tempDic?["currentTag"] = currentTag!
  543. }
  544. cacheMusicData["\(tagId)"] = tempDic ?? Dictionary<String, Any>.init()
  545. } else {
  546. var tempDic: [String: Any] = Dictionary<String, Any>.init()
  547. if tagInfo != nil, (tagInfo?.0.count ?? 0) > 0 {
  548. tempDic["tagInfo"] = tagInfo!
  549. }
  550. if pageList != nil, (pageList?.count ?? 0) > 0 {
  551. tempDic["pageList"] = pageList!
  552. }
  553. if currentTag != nil {
  554. tempDic["currentTag"] = currentTag!
  555. }
  556. cacheMusicData["\(tagId)"] = tempDic
  557. }
  558. }
  559. }
  560. }
  561. extension PQStuckPointMusicController {
  562. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) {
  563. if object is AVPlayerItem, keyPath == "status" {
  564. BFLog(message: "AVPlayerItem - status = \((object as! AVPlayerItem).status.rawValue)")
  565. switch (object as! AVPlayerItem).status {
  566. case .unknown:
  567. break
  568. case .readyToPlay:
  569. break
  570. case .failed:
  571. break
  572. default:
  573. break
  574. }
  575. } else if object is AVPlayerItem, keyPath == "error" {
  576. BFLog(message: "AVPlayerItem - error = \(String(describing: (object as! AVPlayerItem).error))")
  577. }
  578. }
  579. }