// // LNSkillVoiceBarView.swift // Lanu // // Created by OneeChan on 2025/11/30. // import Foundation import UIKit import SnapKit class LNSkillVoiceBarView: UIView { private let durationLabel = UILabel() private var curUrl: String? private let playStateIc = UIImageView() private let voiceWaveView = LNVoiceWaveView() override init(frame: CGRect) { super.init(frame: frame) setupViews() LNEventDeliver.addObserver(self) } func setVoice(_ url: String) { curUrl = url LNVoiceResourceManager.shared.getRemoteAudioDuration(urlStr: url) { [weak self] duration, err in guard let self else { return } guard let duration, err == nil else { return } guard curUrl == url else { return } isHidden = duration <= 0 durationLabel.text = "\(Int(duration.rounded()))\"" } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNSkillVoiceBarView: LNVoicePlayerNotify { func onAudioStartPlay(path: String) { guard path == curUrl else { return } playStateIc.image = .icVoicePause voiceWaveView.startAnimate() } func onAudioStopPlay(path: String) { guard path == curUrl else { return } playStateIc.image = .icVoicePlay voiceWaveView.stopAnimate() LNVoiceResourceManager.shared.getRemoteAudioDuration(urlStr: path) { [weak self] duration, err in guard let self else { return } guard let duration, err == nil else { return } guard curUrl == path else { return } isHidden = duration <= 0 durationLabel.text = "\(Int(duration.rounded()))\"" } } func onAudioUpdateDuration(path: String, cur: TimeInterval, total: TimeInterval) { guard path == curUrl else { return } durationLabel.text = "\(Int((total - cur).rounded()))\"" } } extension LNSkillVoiceBarView { private func setupViews() { isHidden = true snp.makeConstraints { make in make.width.equalTo(86) make.height.equalTo(31) } let button = UIButton() button.setBackgroundImage(.primary_7, for: .normal) button.layer.cornerRadius = 15.5 button.clipsToBounds = true button.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } guard let curUrl else { return } if LNVoicePlayer.shared.playingUrl == curUrl { LNVoicePlayer.shared.stop() } else { LNVoicePlayer.shared.play(curUrl) } }), for: .touchUpInside) addSubview(button) button.snp.makeConstraints { make in make.edges.equalToSuperview() } playStateIc.image = .icVoicePlay addSubview(playStateIc) playStateIc.snp.makeConstraints { make in make.leading.equalToSuperview().offset(8) make.centerY.equalToSuperview() make.width.height.equalTo(22) } voiceWaveView.build() voiceWaveView.isUserInteractionEnabled = false addSubview(voiceWaveView) voiceWaveView.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(playStateIc.snp.trailing).offset(5) make.width.equalTo(18.5) make.height.equalTo(11) } durationLabel.font = .heading_h5 durationLabel.textColor = .text_1 durationLabel.textAlignment = .center addSubview(durationLabel) durationLabel.snp.makeConstraints { make in make.leading.equalTo(voiceWaveView.snp.trailing).offset(4) make.centerY.equalToSuperview() make.trailing.equalToSuperview().offset(-7) } } }