BFMusicSearchController.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //
  2. // BFMusicSearchController.swift
  3. // BFRecordScreenKit
  4. //
  5. // Created by Harry on 2022/3/3.
  6. //
  7. import Foundation
  8. import BFUIKit
  9. import BFMediaKit
  10. import BFCommonKit
  11. import BFNetRequestKit
  12. import Alamofire
  13. import MJRefresh
  14. class BFMusicSearchController: BFBaseViewController {
  15. var choseAction : ((PQVoiceModel?) -> Void)?
  16. var cutActionCallback: ((PQVoiceModel) -> Void)?
  17. var loadedTimeRangesObserver : NSKeyValueObservation?
  18. var chosedIndexPath : IndexPath?
  19. var chosedCellStatu : BFMuicInfoCellState = .pause
  20. var searchResults = [PQVoiceModel]()
  21. var currPage = 1
  22. var keywork : String?
  23. // 试听音乐
  24. let player:AVPlayer = {
  25. let p = AVPlayer(playerItem: nil)
  26. return p
  27. }()
  28. lazy var searchTF : UITextField = {
  29. let searchTF = UITextField()
  30. let leftv = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 20))
  31. let iv = UIImageView(frame: CGRect(x: 6, y: 0, width: 20, height: 20))
  32. iv.contentMode = .scaleAspectFit
  33. iv.image = imageInRecordScreenKit(by: "search")
  34. leftv.addSubview(iv)
  35. searchTF.leftView = leftv
  36. searchTF.leftViewMode = .always
  37. searchTF.clearButtonMode = .whileEditing
  38. let redPlaceholderText = NSAttributedString(string: "歌名/歌手名",
  39. attributes: [NSAttributedString.Key.foregroundColor: UIColor.hexColor(hexadecimal: "#BDBDBD"),NSAttributedString.Key.font:UIFont.systemFont(ofSize: 14,weight: .regular)])
  40. searchTF.attributedPlaceholder = redPlaceholderText
  41. searchTF.font = UIFont.systemFont(ofSize: 14,weight: .regular)
  42. searchTF.delegate = self
  43. searchTF.returnKeyType = .search
  44. searchTF.textColor = UIColor.white
  45. searchTF.backgroundColor = UIColor.hexColor(hexadecimal: "#1d1d1d")
  46. searchTF.layer.cornerRadius = 18
  47. return searchTF
  48. }()
  49. lazy var musicTb : UITableView = {
  50. let tb = UITableView(frame: .zero)
  51. tb.delegate = self
  52. tb.dataSource = self
  53. tb.separatorColor = UIColor.hexColor(hexadecimal: "#272727")
  54. tb.register(BFMusicInfoSearchCell.self, forCellReuseIdentifier: "BFMusicInfoSearchCell")
  55. tb.tableFooterView = UIView()
  56. tb.backgroundColor = .clear
  57. tb.mj_footer = MJRefreshAutoFooter.init(refreshingBlock: {[weak self] in
  58. guard let wself = self else { return }
  59. if wself.searchResults.count > 0 {
  60. wself.requestSearchMusic()
  61. }
  62. })
  63. return tb
  64. }()
  65. override func viewDidAppear(_ animated: Bool) {
  66. super.viewDidAppear(animated)
  67. searchTF.becomeFirstResponder()
  68. }
  69. override func viewDidLoad() {
  70. super.viewDidLoad()
  71. let closeBtn = UIButton()
  72. closeBtn.setImage(imageInRecordScreenKit(by: "search_close"), for: .normal)
  73. closeBtn.frame = CGRect(x: 12, y: statusBarHeight + 2, width: 40, height: 40)
  74. closeBtn.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
  75. view.addSubview(closeBtn)
  76. searchTF.frame = CGRect(x: 62, y: statusBarHeight + 4, width: cScreenWidth - 62 - 18, height: 36)
  77. view.addSubview(searchTF)
  78. view.addSubview(musicTb)
  79. musicTb.snp.makeConstraints { make in
  80. make.left.right.bottom.equalToSuperview()
  81. make.top.equalTo(searchTF.snp.bottom).offset(4)
  82. }
  83. loadedTimeRangesObserver = player.observe(\AVPlayer.currentItem?.loadedTimeRanges, options: [.new, .initial]) { [weak self] (player, change) in
  84. DispatchQueue.main.async {[weak self] in
  85. guard let wself = self else { return }
  86. guard let ranges = change.newValue as? [CMTimeRange] else { return }
  87. if let indx = wself.chosedIndexPath, let cell = wself.musicTb.cellForRow(at: indx) as? BFMuicInfoCell, let totalDur = player.currentItem?.duration, totalDur.isValid, CMTimeCompare(ranges.first?.duration ?? .zero, totalDur) >= 0{
  88. if (player.currentItem?.asset as? AVURLAsset)?.url.absoluteString ?? "b" == cell.data?.musicPath ?? "a" {
  89. if cell.status == .loading{
  90. cell.status = .playing
  91. wself.chosedCellStatu = .playing
  92. }
  93. }
  94. }
  95. // BFLog(1, message: "开始播放音乐:\(ranges.first?.start.seconds ?? 0), dur:\( ranges.first?.duration.seconds ?? 0), tot:\(player.currentItem?.duration.seconds ?? 0)")
  96. }
  97. }
  98. }
  99. func choseCell() -> BFMuicInfoCell? {
  100. if let indpx = chosedIndexPath, let cell = musicTb.cellForRow(at: indpx) as? BFMuicInfoCell {
  101. return cell
  102. }
  103. return nil
  104. }
  105. @objc func closeAction(){
  106. self.dismiss(animated: true, completion: nil)
  107. }
  108. }
  109. extension BFMusicSearchController : UITableViewDelegate, UITableViewDataSource {
  110. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  111. return searchResults.count
  112. }
  113. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  114. let cell = tableView.dequeueReusableCell(withIdentifier: "BFMusicInfoSearchCell")
  115. if let cell = cell as? BFMusicInfoSearchCell{
  116. cell.data = searchResults[indexPath.row]
  117. cell.useCallback = {[weak self, weak cell] in
  118. guard let wself = self else { return }
  119. wself.player.pause()
  120. cell?.status = .pause
  121. wself.choseAction?(cell?.data)
  122. wself.dismiss(animated: true, completion: nil)
  123. }
  124. cell.cutCallBack = {[weak self, weak cell] in
  125. guard let wself = self else { return }
  126. wself.player.pause()
  127. cell?.status = .pause
  128. if let data = cell?.data {
  129. wself.dismiss(animated: true) {[weak self] in
  130. guard let wself = self else { return }
  131. wself.cutActionCallback?(data)
  132. }
  133. }
  134. }
  135. if cell.data?.isSelected ?? false {
  136. chosedIndexPath = indexPath
  137. cell.status = chosedCellStatu
  138. }else{
  139. cell.status = .normal
  140. }
  141. }
  142. cell?.selectionStyle = .none
  143. return cell!
  144. }
  145. func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  146. return 64
  147. }
  148. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  149. if let cell = tableView.cellForRow(at: indexPath) as? BFMusicInfoSearchCell {
  150. if chosedIndexPath == indexPath {
  151. if cell.status != .pause{
  152. cell.status = .pause
  153. player.pause()
  154. }else{
  155. cell.status = .loading
  156. player.play()
  157. }
  158. return
  159. }
  160. cell.changeSelected(true)
  161. chosedIndexPath = indexPath
  162. if cell.status == .normal {
  163. if let urlStr = cell.data?.musicPath, let url = URL(string: urlStr){
  164. BFLog(1, message: "歌曲地址: \(url)")
  165. if url.absoluteString != (player.currentItem?.asset as? AVURLAsset)?.url.absoluteString ?? "b" {
  166. if player.currentItem != nil {
  167. NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
  168. }
  169. player.replaceCurrentItem(with: AVPlayerItem(url: url))
  170. NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: .main) {[weak self] notice in
  171. guard let wself = self else { return }
  172. wself.player.currentItem?.seek(to: .zero, completionHandler: nil)
  173. // wself.choseCell()?.status = .pause
  174. // wself.chosedCellStatu = .pause
  175. wself.player.play()
  176. }
  177. cell.status = .loading
  178. }else {
  179. cell.status = .playing
  180. }
  181. player.play()
  182. }
  183. }else if cell.status == .pause{
  184. player.play()
  185. } else{
  186. player.pause()
  187. cell.status = .pause
  188. }
  189. chosedCellStatu = cell.status
  190. }
  191. }
  192. func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
  193. let cell = tableView.cellForRow(at: indexPath) as? BFMusicInfoSearchCell
  194. cell?.status = .normal
  195. cell?.changeSelected(false)
  196. chosedIndexPath = nil
  197. player.pause()
  198. }
  199. // MARK: - 搜素接口
  200. func requestSearchMusic() {
  201. if keywork?.count ?? 0 < 1 {
  202. cShowHUB(superView: nil, msg: "搜索不能为空")
  203. return
  204. }
  205. BFNetRequestAdaptor.postRequestData(url: PQENVUtil.shared.materialSearchApi + searchBGMMaterialUrl, parames: ["keyWord": keywork, "pageNo": currPage, "pageSize": 20], commonParams: commonParams(), encoding: JSONEncoding.default, isJsonEncodingNormal: true) { [weak self] response, _, error, _ in
  206. DispatchQueue.global().async {[weak self] in
  207. guard let wself = self else { return }
  208. var bgmList = [PQVoiceModel]()
  209. if response is NSNull || response == nil {
  210. DispatchQueue.main.async {
  211. cShowHUB(superView: nil, msg: "网络连接失败,请检查网络后重试")
  212. }
  213. return
  214. }
  215. let tempArr = (response as? [String: Any])?["entityList"] as? [[String: Any]]
  216. if tempArr != nil {
  217. for item in tempArr! {
  218. let tempModel = PQVoiceModel(jsonDict: item)
  219. tempModel.volume = 30
  220. tempModel.voiceType = VOICETYPT.BGM.rawValue
  221. bgmList.append(tempModel)
  222. }
  223. }
  224. if wself.currPage == 1 {
  225. wself.searchResults.removeAll()
  226. }
  227. wself.searchResults.append(contentsOf: bgmList)
  228. wself.currPage += 1
  229. DispatchQueue.main.async {[weak self] in
  230. guard let wself = self else { return }
  231. if wself.searchResults.count > 0 {
  232. // wself.musicTb.tableFooterView = UIView()
  233. }else{
  234. wself.musicTb.tableFooterView = wself.createNoDataView()
  235. }
  236. wself.musicTb.reloadData()
  237. }
  238. }
  239. }
  240. }
  241. func createNoDataView() -> UIView {
  242. let back = UIView(frame: CGRect(x: 0, y: 0, width: cScreenWidth, height: 200))
  243. let l = UILabel(frame: CGRect(x: 40, y: 60, width: cScreenWidth - 80, height: 80))
  244. l.text = "没有搜索到相关音乐\n换个词再试试吧"
  245. l.textColor = UIColor.hexColor(hexadecimal: "#787878")
  246. l.textAlignment = .center
  247. l.numberOfLines = 2
  248. l.font = UIFont.systemFont(ofSize: 17)
  249. back.addSubview(l)
  250. return back
  251. }
  252. func resetRearch() {
  253. player.pause()
  254. chosedCellStatu = .normal
  255. chosedIndexPath = nil
  256. currPage = 1
  257. }
  258. }
  259. extension BFMusicSearchController : UITextFieldDelegate {
  260. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  261. if let keyword = textField.text, keyword.replacingOccurrences(of: " ", with: "", options: .literal, range: nil).count > 0 {
  262. resetRearch()
  263. keywork = keyword
  264. requestSearchMusic()
  265. }else{
  266. cShowHUB(superView: nil, msg: "搜索不能为空")
  267. }
  268. textField.resignFirstResponder()
  269. return true
  270. }
  271. }