LNJoinUsVoiceExamplePanel.swift 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //
  2. // LNJoinUsVoiceExamplePanel.swift
  3. // Gami
  4. //
  5. // Created by OneeChan on 2026/1/22.
  6. //
  7. import Foundation
  8. import UIKit
  9. import SnapKit
  10. class LNJoinUsVoiceExamplePanel: LNPopupView {
  11. private let titleLabel = UILabel()
  12. private let descLabel = UILabel()
  13. private let playIcon = UIImageView()
  14. private let voiceWaveView = LNVoiceWaveView()
  15. private let playDurationLabel = UILabel()
  16. private var curItem: LNSkillFieldExample?
  17. override init(frame: CGRect) {
  18. super.init(frame: frame)
  19. setupViews()
  20. LNEventDeliver.addObserver(self)
  21. }
  22. func update(_ example: LNSkillFieldExample) {
  23. curItem = example
  24. updateDuration()
  25. }
  26. required init?(coder: NSCoder) {
  27. fatalError("init(coder:) has not been implemented")
  28. }
  29. }
  30. extension LNJoinUsVoiceExamplePanel: LNVoicePlayerNotify {
  31. func onAudioUpdateDuration(path: String, cur: TimeInterval, total: TimeInterval) {
  32. guard curItem?.value == path else { return }
  33. let remain = Int(total - cur)
  34. playDurationLabel.text = "\(remain)“"
  35. }
  36. func onAudioStopPlay(path: String) {
  37. guard curItem?.value == path else { return }
  38. updateDuration()
  39. playIcon.image = .icVoicePlay
  40. voiceWaveView.stopAnimate()
  41. }
  42. func onAudioStartPlay(path: String) {
  43. guard curItem?.value == path else { return }
  44. playIcon.image = .icVoicePause
  45. voiceWaveView.startAnimate()
  46. }
  47. }
  48. extension LNJoinUsVoiceExamplePanel {
  49. private func updateDuration() {
  50. guard let url = curItem?.value else { return }
  51. LNVoiceResourceManager.shared.getRemoteAudioDuration(urlStr: url) { [weak self] duration, _ in
  52. guard let self else { return }
  53. guard let duration else { return }
  54. let intDuration = Int(duration)
  55. playDurationLabel.text = "\(intDuration)“"
  56. }
  57. }
  58. private func setupViews() {
  59. let headerView = buildHeader()
  60. container.addSubview(headerView)
  61. headerView.snp.makeConstraints { make in
  62. make.horizontalEdges.equalToSuperview().inset(32)
  63. make.top.equalToSuperview()
  64. }
  65. let playView = buildPlayView()
  66. container.addSubview(playView)
  67. playView.snp.makeConstraints { make in
  68. make.horizontalEdges.equalToSuperview()
  69. make.top.equalTo(headerView.snp.bottom)
  70. make.bottom.equalToSuperview().offset(commonBottomInset)
  71. }
  72. }
  73. private func buildHeader() -> UIView {
  74. let container = UIView()
  75. titleLabel.font = .heading_h3
  76. titleLabel.textColor = .text_5
  77. titleLabel.numberOfLines = 0
  78. titleLabel.textAlignment = .center
  79. container.addSubview(titleLabel)
  80. titleLabel.snp.makeConstraints { make in
  81. make.horizontalEdges.equalToSuperview().inset(32)
  82. make.top.equalToSuperview().offset(13)
  83. }
  84. descLabel.font = .body_xs
  85. descLabel.textColor = .text_3
  86. descLabel.numberOfLines = 0
  87. descLabel.textAlignment = .center
  88. container.addSubview(descLabel)
  89. descLabel.snp.makeConstraints { make in
  90. make.horizontalEdges.equalToSuperview().inset(32)
  91. make.bottom.equalToSuperview().offset(-13)
  92. make.top.equalTo(titleLabel.snp.bottom).offset(2)
  93. }
  94. return container
  95. }
  96. private func buildPlayView() -> UIView {
  97. let playView = UIView()
  98. let button = UIButton()
  99. button.setBackgroundImage(.primary_7, for: .normal)
  100. button.layer.cornerRadius = 16
  101. button.clipsToBounds = true
  102. button.addAction(UIAction(handler: { [weak self] _ in
  103. guard let self else { return }
  104. if LNVoicePlayer.shared.isPlaying {
  105. LNVoicePlayer.shared.stop()
  106. } else if let url = curItem?.value {
  107. LNVoicePlayer.shared.play(url)
  108. }
  109. }), for: .touchUpInside)
  110. playView.addSubview(button)
  111. button.snp.makeConstraints { make in
  112. make.centerX.equalToSuperview()
  113. make.top.equalToSuperview().offset(20)
  114. make.bottom.equalToSuperview().offset(-50)
  115. make.width.equalTo(163)
  116. make.height.equalTo(32)
  117. }
  118. playIcon.image = .icVoicePlay
  119. button.addSubview(playIcon)
  120. playIcon.snp.makeConstraints { make in
  121. make.centerY.equalToSuperview()
  122. make.leading.equalToSuperview().offset(3)
  123. make.width.height.equalTo(22)
  124. }
  125. voiceWaveView.build()
  126. button.addSubview(voiceWaveView)
  127. voiceWaveView.snp.makeConstraints { make in
  128. make.centerY.equalToSuperview()
  129. make.leading.equalTo(playIcon.snp.trailing).offset(7)
  130. make.width.equalTo(18)
  131. make.height.equalTo(11)
  132. }
  133. playDurationLabel.font = .heading_h5
  134. playDurationLabel.textColor = .text_1
  135. button.addSubview(playDurationLabel)
  136. playDurationLabel.snp.makeConstraints { make in
  137. make.centerY.equalToSuperview()
  138. make.trailing.equalToSuperview().offset(-8)
  139. }
  140. return playView
  141. }
  142. }