|
@@ -1,69 +1,296 @@
|
|
|
package com.adealink.weparty.im.session.adapter.viewbinder
|
|
package com.adealink.weparty.im.session.adapter.viewbinder
|
|
|
|
|
|
|
|
|
|
+import android.os.Build
|
|
|
import android.view.LayoutInflater
|
|
import android.view.LayoutInflater
|
|
|
import android.view.ViewGroup
|
|
import android.view.ViewGroup
|
|
|
|
|
+import com.adealink.frame.aab.util.getCompatColor
|
|
|
|
|
+import com.adealink.frame.log.Log
|
|
|
import com.adealink.frame.util.onClick
|
|
import com.adealink.frame.util.onClick
|
|
|
|
|
+import com.adealink.frame.util.runOnUiThread
|
|
|
|
|
+import com.adealink.weparty.commonui.ext.gone
|
|
|
|
|
+import com.adealink.weparty.commonui.ext.show
|
|
|
|
|
+import com.adealink.weparty.commonui.util.formatSecondsTo00
|
|
|
|
|
+import com.adealink.weparty.im.R
|
|
|
|
|
+import com.adealink.weparty.im.databinding.LayoutSessionMessageBaseBinding
|
|
|
import com.adealink.weparty.im.databinding.LayoutSessionMessageSoundBinding
|
|
import com.adealink.weparty.im.databinding.LayoutSessionMessageSoundBinding
|
|
|
|
|
+import com.adealink.weparty.module.im.data.TAG_IM_SESSION_SOUND
|
|
|
import com.adealink.weparty.util.formatTimeTo
|
|
import com.adealink.weparty.util.formatTimeTo
|
|
|
|
|
+import com.adealink.weparty.util.isSupportSpeedPlay
|
|
|
|
|
+import com.tencent.qcloud.tuicore.interfaces.TUIValueCallback
|
|
|
|
|
+import com.tencent.qcloud.tuicore.util.ToastUtil
|
|
|
|
|
+import com.tencent.qcloud.tuikit.timcommon.interfaces.OnItemClickListener
|
|
|
|
|
+import com.tencent.qcloud.tuikit.timcommon.util.DateTimeUtil
|
|
|
|
|
+import com.tencent.qcloud.tuikit.timcommon.util.FileUtil
|
|
|
|
|
+import com.tencent.qcloud.tuikit.tuichat.TUIChatService
|
|
|
import com.tencent.qcloud.tuikit.tuichat.bean.message.SoundMessageBean
|
|
import com.tencent.qcloud.tuikit.tuichat.bean.message.SoundMessageBean
|
|
|
|
|
+import com.tencent.qcloud.tuikit.tuichat.component.audio.AudioPlayer
|
|
|
|
|
+import com.tencent.qcloud.tuikit.tuichat.presenter.ChatFileDownloadPresenter
|
|
|
import java.util.Timer
|
|
import java.util.Timer
|
|
|
|
|
+import java.util.TimerTask
|
|
|
|
|
+import kotlin.math.max
|
|
|
|
|
+import kotlin.math.min
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 对照: SoundMessageHolder
|
|
* 对照: SoundMessageHolder
|
|
|
*/
|
|
*/
|
|
|
-class SoundMessageViewBinder() :
|
|
|
|
|
- BaseMessageViewBinder<SoundMessageBean, LayoutSessionMessageSoundBinding>() {
|
|
|
|
|
|
|
+
|
|
|
|
|
+class SoundMessageViewHolder(
|
|
|
|
|
+ rootBinding: LayoutSessionMessageBaseBinding,
|
|
|
|
|
+ binging: LayoutSessionMessageSoundBinding
|
|
|
|
|
+) : MessageViewHolder<SoundMessageBean, LayoutSessionMessageSoundBinding>(rootBinding, binging) {
|
|
|
|
|
+
|
|
|
|
|
+ companion object {
|
|
|
|
|
+ val PLAY_SPEED = arrayOf(1f, 2f, 3f)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
private var mTimer: Timer? = null
|
|
private var mTimer: Timer? = null
|
|
|
|
|
+ private var times = 0
|
|
|
|
|
+ private var playSpeedIndex = 0
|
|
|
|
|
+
|
|
|
|
|
+ private var downloadSoundCallback: TUIValueCallback<*>? = null
|
|
|
|
|
|
|
|
override fun onBindSelfMessage(
|
|
override fun onBindSelfMessage(
|
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
|
- item: SoundMessageBean
|
|
|
|
|
|
|
+ msg: SoundMessageBean
|
|
|
) {
|
|
) {
|
|
|
- setSound(binding, item)
|
|
|
|
|
- setMessageTime(binding, item)
|
|
|
|
|
|
|
+ initView(binding, msg)
|
|
|
|
|
+ setMessageTime(binding, msg)
|
|
|
|
|
+ //倍数播放
|
|
|
|
|
+ binding.btnOtherSpeed.gone()
|
|
|
|
|
+ if (isSupportSpeedPlay()) {
|
|
|
|
|
+ binding.btnSelfSpeed.show()
|
|
|
|
|
+ binding.btnSelfSpeed.onClick {
|
|
|
|
|
+ changeClaySpeed(binding, msg)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ binding.btnSelfSpeed.gone()
|
|
|
|
|
+ }
|
|
|
|
|
+ //播放进度颜色
|
|
|
|
|
+ binding.vPlayView.setColor(
|
|
|
|
|
+ lineColor = getCompatColor(R.color.im_sound_play_self_line_color),
|
|
|
|
|
+ lineHintColor = getCompatColor(R.color.im_sound_play_self_line_hint_color),
|
|
|
|
|
+ cursorColor = getCompatColor(R.color.im_sound_play_self_cursor_color)
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
override fun onBindOtherMessage(
|
|
override fun onBindOtherMessage(
|
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
|
- item: SoundMessageBean
|
|
|
|
|
|
|
+ msg: SoundMessageBean
|
|
|
) {
|
|
) {
|
|
|
- setSound(binding, item)
|
|
|
|
|
- setMessageTime(binding, item)
|
|
|
|
|
|
|
+ initView(binding, msg)
|
|
|
|
|
+ setMessageTime(binding, msg)
|
|
|
|
|
+ //倍数播放
|
|
|
|
|
+ binding.btnSelfSpeed.gone()
|
|
|
|
|
+ if (isSupportSpeedPlay()) {
|
|
|
|
|
+ binding.btnOtherSpeed.show()
|
|
|
|
|
+ binding.btnOtherSpeed.onClick {
|
|
|
|
|
+ changeClaySpeed(binding, msg)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ binding.btnOtherSpeed.gone()
|
|
|
|
|
+ }
|
|
|
|
|
+ //播放进度颜色
|
|
|
|
|
+ binding.vPlayView.setColor(
|
|
|
|
|
+ lineColor = getCompatColor(R.color.im_sound_play_other_line_color),
|
|
|
|
|
+ lineHintColor = getCompatColor(R.color.im_sound_play_other_line_hint_color),
|
|
|
|
|
+ cursorColor = if (msg.isUnread) {
|
|
|
|
|
+ getCompatColor(R.color.im_sound_play_other_cursor_color)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ getCompatColor(R.color.im_sound_play_other_cursor_read_color)
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private fun setSound(
|
|
|
|
|
|
|
+ private fun initView(
|
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
|
- message: SoundMessageBean
|
|
|
|
|
|
|
+ msg: SoundMessageBean
|
|
|
) {
|
|
) {
|
|
|
- val duration = message.getDuration()
|
|
|
|
|
- binding.tvDuration.text = duration.toString()
|
|
|
|
|
|
|
+ val durationStr = formatSecondsTo00(max(msg.getDuration(), 1)) //音频时间最小展示1s
|
|
|
|
|
+ resetTimerStatus(binding, durationStr)
|
|
|
|
|
+ binding.root.onClick {
|
|
|
|
|
+ onSoundClick(binding, msg, msg.getDuration(), durationStr)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private fun setMessageTime(
|
|
|
|
|
|
|
+ private fun resetTimerStatus(
|
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
binding: LayoutSessionMessageSoundBinding,
|
|
|
- item: SoundMessageBean
|
|
|
|
|
|
|
+ timeString: String?
|
|
|
) {
|
|
) {
|
|
|
- binding.tvTime.text = formatTimeTo((item.messageTime * 1000), "HH:mm")
|
|
|
|
|
|
|
+ mTimer?.cancel()
|
|
|
|
|
+ mTimer = null
|
|
|
|
|
+ times = 0
|
|
|
|
|
+ playSpeedIndex = 0
|
|
|
|
|
+ binding.tvSelfSpeed.text = "1"
|
|
|
|
|
+ binding.tvOtherSpeed.text = "1"
|
|
|
|
|
+ binding.vPlayView.stop()
|
|
|
|
|
+ binding.tvDuration.text = timeString
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- override fun onCreateMessageContent(
|
|
|
|
|
- inflater: LayoutInflater,
|
|
|
|
|
- parent: ViewGroup
|
|
|
|
|
- ): LayoutSessionMessageSoundBinding {
|
|
|
|
|
- return LayoutSessionMessageSoundBinding.inflate(inflater, parent, true).apply {
|
|
|
|
|
- initView(this)
|
|
|
|
|
|
|
+ private fun isPlaying(message: SoundMessageBean): Boolean {
|
|
|
|
|
+ val soundPath = ChatFileDownloadPresenter.getSoundPath(message)
|
|
|
|
|
+ return AudioPlayer.getInstance().isPlaying()
|
|
|
|
|
+ && AudioPlayer.getInstance().path == soundPath
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun onSoundClick(
|
|
|
|
|
+ binding: LayoutSessionMessageSoundBinding,
|
|
|
|
|
+ message: SoundMessageBean,
|
|
|
|
|
+ soundSecond: Int,
|
|
|
|
|
+ soundDurationStr: String?
|
|
|
|
|
+ ) {
|
|
|
|
|
+ val soundPath = ChatFileDownloadPresenter.getSoundPath(message)
|
|
|
|
|
+ if (AudioPlayer.getInstance().isPlaying()) {
|
|
|
|
|
+ AudioPlayer.getInstance().stopPlay()
|
|
|
|
|
+ resetTimerStatus(binding, soundDurationStr)
|
|
|
|
|
+ if (AudioPlayer.getInstance().path == soundPath) {
|
|
|
|
|
+ //播放同一个音频
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!FileUtil.isFileExists(soundPath)) {
|
|
|
|
|
+ ToastUtil.toastShortMessage(
|
|
|
|
|
+ TUIChatService.getAppContext()
|
|
|
|
|
+ .getString(R.string.im_sound_play_tip_for_voice_not_download)
|
|
|
|
|
+ )
|
|
|
|
|
+ getSound(message)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (soundSecond > 1) {
|
|
|
|
|
+ //音频时间大于1s才启动定时器
|
|
|
|
|
+ if (mTimer == null) {
|
|
|
|
|
+ mTimer = Timer()
|
|
|
|
|
+ }
|
|
|
|
|
+ mTimer?.schedule(object : TimerTask() {
|
|
|
|
|
+ override fun run() {
|
|
|
|
|
+ runOnUiThread {
|
|
|
|
|
+ if (times < soundSecond) {
|
|
|
|
|
+ times = min(times + PLAY_SPEED[playSpeedIndex].toInt(), soundSecond)
|
|
|
|
|
+ val s = DateTimeUtil.formatSecondsTo00(times)
|
|
|
|
|
+ binding.tvDuration.text = s
|
|
|
|
|
+ } else {
|
|
|
|
|
+ binding.tvDuration.text = soundDurationStr
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 0, 1000)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ val soundPlayButton = binding.btnPlay
|
|
|
|
|
+ soundPlayButton.setImageResource(R.drawable.im_session_sound_stop_ic)
|
|
|
|
|
+ message.setPlayed()
|
|
|
|
|
+ AudioPlayer.getInstance().startPlay(soundPath, object : AudioPlayer.Callback {
|
|
|
|
|
+
|
|
|
|
|
+ override fun onCompletion(success: Boolean?) {
|
|
|
|
|
+ Log.d(
|
|
|
|
|
+ TAG_IM_SESSION_SOUND,
|
|
|
|
|
+ "onSoundClick, onCompletion, message:$message"
|
|
|
|
|
+ )
|
|
|
|
|
+ soundPlayButton.post {
|
|
|
|
|
+ soundPlayButton.setImageResource(R.drawable.im_session_sound_play_ic)
|
|
|
|
|
+ }
|
|
|
|
|
+ resetTimerStatus(binding, soundDurationStr)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ startPlayAnimation(
|
|
|
|
|
+ binding,
|
|
|
|
|
+ soundSecond * 1000L,
|
|
|
|
|
+ 0,
|
|
|
|
|
+ PLAY_SPEED[playSpeedIndex]
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun startPlayAnimation(
|
|
|
|
|
+ binding: LayoutSessionMessageSoundBinding,
|
|
|
|
|
+ allDuration: Long, //所有时长(毫秒)
|
|
|
|
|
+ duration: Long, //剩余时长(毫秒)
|
|
|
|
|
+ speed: Float, //倍速
|
|
|
|
|
+ ) {
|
|
|
|
|
+ val soundPlayView = binding.vPlayView
|
|
|
|
|
+ soundPlayView.start(allDuration, duration, speed)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ private fun getSound(messageBean: SoundMessageBean?) {
|
|
|
|
|
+ downloadSoundCallback = object : TUIValueCallback<Any?>() {
|
|
|
|
|
+ override fun onProgress(currentSize: Long, totalSize: Long) {
|
|
|
|
|
+ Log.d(
|
|
|
|
|
+ TAG_IM_SESSION_SOUND,
|
|
|
|
|
+ "downloadSound progress current: $currentSize, total:$totalSize"
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun onError(code: Int, desc: String?) {
|
|
|
|
|
+ Log.e(TAG_IM_SESSION_SOUND, "getSoundToFile failed code = $code, info = $desc")
|
|
|
|
|
+ //ToastUtil.toastLongMessage("getSoundToFile failed code = " + code + ", info = " + desc)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun onSuccess(obj: Any?) {
|
|
|
|
|
+ Log.d(TAG_IM_SESSION_SOUND, "get sound success")
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ ChatFileDownloadPresenter.downloadSound(messageBean, downloadSoundCallback)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private fun initView(binding: LayoutSessionMessageSoundBinding) {
|
|
|
|
|
- binding.btnPlay.onClick {
|
|
|
|
|
- binding.vPlayView.start(5_000)
|
|
|
|
|
|
|
+ private fun changeClaySpeed(
|
|
|
|
|
+ binding: LayoutSessionMessageSoundBinding,
|
|
|
|
|
+ message: SoundMessageBean
|
|
|
|
|
+ ) {
|
|
|
|
|
+ if (!isPlaying(message)) {
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
|
|
+ playSpeedIndex = (playSpeedIndex + 1) % PLAY_SPEED.size
|
|
|
|
|
+ val nextSpeed = PLAY_SPEED[playSpeedIndex]
|
|
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
|
+ AudioPlayer.getInstance().setSpeed(nextSpeed)
|
|
|
|
|
+ if (message.isSelf) {
|
|
|
|
|
+ binding.tvSelfSpeed.text = nextSpeed.toInt().toString()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ binding.tvOtherSpeed.text = nextSpeed.toInt().toString()
|
|
|
|
|
+ }
|
|
|
|
|
+ Log.d(TAG_IM_SESSION_SOUND, "changeClaySpeed, speed: $nextSpeed")
|
|
|
|
|
+ Log.d(
|
|
|
|
|
+ TAG_IM_SESSION_SOUND,
|
|
|
|
|
+ " : allTime: ${message.duration * 1000}, currentTim:${AudioPlayer.getInstance().playPosition.toLong()}"
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ startPlayAnimation(
|
|
|
|
|
+ binding,
|
|
|
|
|
+ message.duration * 1000L,
|
|
|
|
|
+ AudioPlayer.getInstance().playPosition.toLong(),
|
|
|
|
|
+ nextSpeed
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun setMessageTime(
|
|
|
|
|
+ binding: LayoutSessionMessageSoundBinding,
|
|
|
|
|
+ item: SoundMessageBean
|
|
|
|
|
+ ) {
|
|
|
|
|
+ binding.tvTime.text = formatTimeTo((item.messageTime * 1000), "HH:mm")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- override fun onViewRecycled(holder: MessageBinding<LayoutSessionMessageSoundBinding>) {
|
|
|
|
|
- super.onViewRecycled(holder)
|
|
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class SoundMessageViewBinder(
|
|
|
|
|
+ onItemClickListener: OnItemClickListener
|
|
|
|
|
+) : BaseMessageViewBinder<SoundMessageBean, LayoutSessionMessageSoundBinding, SoundMessageViewHolder>(
|
|
|
|
|
+ onItemClickListener
|
|
|
|
|
+) {
|
|
|
|
|
+
|
|
|
|
|
+ override fun onCreateMessageHolder(
|
|
|
|
|
+ rootBinder: LayoutSessionMessageBaseBinding,
|
|
|
|
|
+ inflater: LayoutInflater,
|
|
|
|
|
+ parent: ViewGroup
|
|
|
|
|
+ ): SoundMessageViewHolder {
|
|
|
|
|
+ return SoundMessageViewHolder(
|
|
|
|
|
+ rootBinder,
|
|
|
|
|
+ LayoutSessionMessageSoundBinding.inflate(
|
|
|
|
|
+ inflater,
|
|
|
|
|
+ parent,
|
|
|
|
|
+ true
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|