DoggyZhang пре 2 месеци
родитељ
комит
b37cea5d83

+ 1 - 1
app/src/main/java/com/adealink/weparty/module/order/data/OrderDetailInfo.kt

@@ -213,7 +213,7 @@ data class QueryUnCompleteOrderRes(
 
 data class CreateOrderRes(
     @SerializedName("orderNo") val orderId: String, //订单编号
-    @SerializedName("goldCoinBalance") val balance: Int, //金币余额
+    @SerializedName("goldCoinBalance") val balance: Double, //金币余额
 )
 
 data class OrderPlaymateOpReq(

+ 6 - 1
app/src/main/java/com/adealink/weparty/module/playmate/widget/SoundView.kt

@@ -344,6 +344,12 @@ class SoundView @JvmOverloads constructor(
     private fun startPlay(soundPath: String) {
         AudioPlayer.getInstance().stopPlay()
         AudioPlayer.getInstance().startPlay(soundPath, object : AudioPlayer.Callback {
+            override fun onPlayStart() {
+                if (isAttachedToWindow && soundPath == this@SoundView.voiceData?.path) {
+                    onStartPlay()
+                }
+            }
+
             override fun onCompletion(success: Boolean?) {
                 if (isAttachedToWindow && soundPath == this@SoundView.voiceData?.path) {
                     runOnUiThread {
@@ -352,7 +358,6 @@ class SoundView @JvmOverloads constructor(
                 }
             }
         })
-        onStartPlay()
     }
 
     fun stopPlay() {

BIN
app/src/main/res/drawable-xhdpi/profile_edit_talent_voice_preview_pause_ic.png


+ 6 - 0
frame/tuikit/TUIChat/tuichat/src/main/java/com/tencent/qcloud/tuikit/tuichat/classicui/widget/message/MessageRecyclerView.java

@@ -704,6 +704,12 @@ public class MessageRecyclerView extends RecyclerView implements IMessageRecycle
         messageBean.setPlayed();
         updateMessageView(messageBean);
         AudioPlayer.getInstance().startPlay(soundPath, new AudioPlayer.Callback() {
+
+            @Override
+            public void onPlayStart() {
+
+            }
+
             @Override
             public void onCompletion(Boolean success) {
                 messageBean.setPlaying(false);

+ 33 - 2
frame/tuikit/TUIChat/tuichat/src/main/java/com/tencent/qcloud/tuikit/tuichat/component/audio/AudioPlayer.java

@@ -22,7 +22,8 @@ public class AudioPlayer {
     private String mAudioPath;
     private MediaPlayer mPlayer;
 
-    private AudioPlayer() {}
+    private AudioPlayer() {
+    }
 
     public static AudioPlayer getInstance() {
         return sInstance;
@@ -53,6 +54,7 @@ public class AudioPlayer {
             });
             mPlayer.prepare();
             mPlayer.start();
+            onPlayStart();
         } catch (Exception e) {
             TUIChatLog.w(TAG, "startPlay failed", e);
             ToastUtil.toastLongMessage(TUIChatService.getAppContext().getString(R.string.play_error_tip));
@@ -75,7 +77,6 @@ public class AudioPlayer {
 
     /**
      * 设置播放速度
-     *
      * 1x, 1f
      * 2x, 2f
      * 3x, 3f
@@ -94,6 +95,28 @@ public class AudioPlayer {
         }
     }
 
+    public void pausePlay() {
+        if (mPlayer == null || !mPlayer.isPlaying()) {
+            return;
+        }
+        try {
+            mPlayer.pause();
+        } catch (Exception e) {
+            TUIChatLog.e(TAG, "pause error, " + e.getMessage());
+        }
+    }
+
+    public void resumePlay() {
+        if (mPlayer == null) {
+            return;
+        }
+        try {
+            mPlayer.start();
+        } catch (Exception e) {
+            TUIChatLog.e(TAG, "resume error, " + e.getMessage());
+        }
+    }
+
     public void stopPlay() {
         stopInternalPlay();
         onPlayCompleted(false);
@@ -115,6 +138,12 @@ public class AudioPlayer {
         return false;
     }
 
+    private void onPlayStart() {
+        if (mPlayCallback != null) {
+            mPlayCallback.onPlayStart();
+        }
+    }
+
     private void onPlayCompleted(boolean success) {
         if (mPlayCallback != null) {
             mPlayCallback.onCompletion(success);
@@ -134,6 +163,8 @@ public class AudioPlayer {
     }
 
     public interface Callback {
+        void onPlayStart();
+
         void onCompletion(Boolean success);
     }
 }

+ 5 - 0
frame/tuikit/TUIChat/tuichat/src/main/java/com/tencent/qcloud/tuikit/tuichat/minimalistui/widget/message/viewholder/SoundMessageHolder.java

@@ -107,6 +107,11 @@ public class SoundMessageHolder extends MessageContentHolder {
                 audioPlayImage.setImageResource(R.drawable.chat_audio_stop_btn_ic);
                 message.setPlayed();
                 AudioPlayer.getInstance().startPlay(soundPath, new AudioPlayer.Callback() {
+                    @Override
+                    public void onPlayStart() {
+
+                    }
+
                     @Override
                     public void onCompletion(Boolean success) {
                         audioPlayImage.post(new Runnable() {

+ 15 - 10
module/im/src/main/java/com/adealink/weparty/im/session/adapter/viewbinder/SoundMessageViewBinder.kt

@@ -8,12 +8,12 @@ import com.adealink.frame.log.Log
 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.isViewValid
 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.LayoutSessionMessageTextBinding
 import com.adealink.weparty.module.im.data.TAG_IM_SESSION_SOUND
 import com.adealink.weparty.util.formatTimeTo
 import com.adealink.weparty.util.isSupportSpeedPlay
@@ -24,7 +24,6 @@ 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.TextMessageBean
 import com.tencent.qcloud.tuikit.tuichat.component.audio.AudioPlayer
 import com.tencent.qcloud.tuikit.tuichat.presenter.ChatFileDownloadPresenter
 import java.util.Timer
@@ -167,22 +166,28 @@ class SoundMessageViewHolder(
         binding.btnPlay.setImageResource(R.drawable.im_session_sound_stop_ic)
         message.setPlayed()
         AudioPlayer.getInstance().startPlay(soundPath, object : AudioPlayer.Callback {
+            override fun onPlayStart() {
+                if (isViewValid()) {
+                    startPlayAnimation(
+                        binding,
+                        soundSecond * 1000L,
+                        0,
+                        PLAY_SPEED[playSpeedIndex]
+                    )
+                    showSpeedBtn(binding, message, true)
+                }
+            }
 
             override fun onCompletion(success: Boolean?) {
                 Log.d(
                     TAG_IM_SESSION_SOUND,
                     "onSoundClick, onCompletion, message:$message"
                 )
-                resetTimerStatus(binding, soundDurationStr)
+                if (isViewValid()) {
+                    resetTimerStatus(binding, soundDurationStr)
+                }
             }
         })
-        startPlayAnimation(
-            binding,
-            soundSecond * 1000L,
-            0,
-            PLAY_SPEED[playSpeedIndex]
-        )
-        showSpeedBtn(binding, message, true)
     }
 
     private fun showSpeedBtn(

+ 130 - 29
module/profile/src/main/java/com/adealink/weparty/profile/edit/dialog/fragment/VoiceEditFragment.kt

@@ -36,6 +36,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine
 import java.util.Timer
 import java.util.TimerTask
 import kotlin.coroutines.resume
+import kotlin.math.max
 import com.adealink.weparty.R as APP_R
 
 class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
@@ -52,11 +53,15 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
 
     private val profileViewModel by activityViewModels<ProfileViewModel> { ProfileViewModelFactory() }
 
-    private var mTimer: Timer? = null
-    private var times = 0
-
+    private var recordTimer: Timer? = null
+    private var recordTimes = 0
     private var isRecording: Boolean = false
 
+
+    private var previewTimer: Timer? = null
+    private var previewTimes = 0
+    private var isPreviewPause = false
+
     override fun initViews() {
         super.initViews()
         binding.btnRecord.onClick {
@@ -84,6 +89,8 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
                 binding.clRecord.gone()
                 binding.clPreview.show()
                 binding.btnSubmit.isEnabled = true
+                previewTimes = editViewModel.getRecordDuration()
+                binding.tvPreviewDuration.text = formatMissTime(previewTimes)
             }
         }
     }
@@ -110,12 +117,29 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
     }
 
     private fun audioPreview() {
+        stopRecord()
         val voicePath = editViewModel.voiceDataLD.value?.path
         if (voicePath.isNullOrEmpty()) {
             return
         }
         AudioPlayer.getInstance().stopPlay()
-        AudioPlayer.getInstance().startPlay(voicePath) { }
+        AudioPlayer.getInstance().startPlay(voicePath, object : AudioPlayer.Callback {
+            override fun onPlayStart() {
+                Log.d(TAG, "audioPreview, onPlayStart")
+                if (!isViewBindingValid()) {
+                    return
+                }
+                onPreviewStart()
+            }
+
+            override fun onCompletion(success: Boolean?) {
+                Log.d(TAG, "audioPreview, onCompletion")
+                if (!isViewBindingValid()) {
+                    return
+                }
+                resetPreview()
+            }
+        })
     }
 
     private fun startRecord() {
@@ -126,27 +150,17 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
         val audioPath = "${FilePath.audioPath}voice_edit.m4a"
         AudioRecorder.startRecord(audioPath, object : AudioRecorderCallback {
             override fun onStarted() {
-                Log.d(TAG, "startAudioRecord, onStarted")
-                isRecording = true
-                if (mTimer == null) {
-                    mTimer = Timer()
+                if (!isViewBindingValid()) {
+                    return
                 }
-                mTimer?.schedule(object : TimerTask() {
-                    override fun run() {
-                        runOnUiThread {
-                            times++
-                            if (isViewBindingValid()) {
-                                binding.tvDuration.text = formatMissTime(times)
-                            }
-                        }
-                    }
-                }, 0, 1000)
-                binding.tvDurationTips.text =
-                    getCompatString(R.string.profile_edit_talent_voice_stop)
-                binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_stop_ic)
+                Log.d(TAG, "startAudioRecord, onStarted")
+                onRecordStart()
             }
 
             override fun onFinished(outputPath: String?) {
+                if (!isViewBindingValid()) {
+                    return
+                }
                 Log.d(TAG, "startAudioRecord, onFinished:$outputPath")
                 resetRecord()
                 val duration = AudioRecorder.getDuration(outputPath)
@@ -159,6 +173,9 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
             }
 
             override fun onFailed(errorCode: Int, errorMessage: String?) {
+                if (!isViewBindingValid()) {
+                    return
+                }
                 Log.d(
                     TAG,
                     "startAudioRecord, onFailed, errorCode:$errorCode, errorMessage:$errorMessage"
@@ -180,6 +197,9 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
             }
 
             override fun onCanceled() {
+                if (!isViewBindingValid()) {
+                    return
+                }
                 Log.d(TAG, "startAudioRecord, onCanceled")
                 resetRecord()
                 binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
@@ -224,6 +244,26 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
         }
     }
 
+    private fun onRecordStart() {
+        isRecording = true
+        if (recordTimer == null) {
+            recordTimer = Timer()
+        }
+        recordTimer?.schedule(object : TimerTask() {
+            override fun run() {
+                runOnUiThread {
+                    recordTimes++
+                    if (isViewBindingValid()) {
+                        binding.tvDuration.text = formatMissTime(recordTimes)
+                    }
+                }
+            }
+        }, 0, 1000)
+        binding.tvDurationTips.text =
+            getCompatString(R.string.profile_edit_talent_voice_stop)
+        binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_stop_ic)
+    }
+
     private fun stopRecord() {
         AudioRecorder.stopRecord()
     }
@@ -231,13 +271,69 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
     @SuppressLint("SetTextI18n")
     private fun resetRecord() {
         isRecording = false
-        mTimer?.cancel()
-        mTimer = null
-        times = 0
-        if (isViewBindingValid()) {
-            binding.tvDuration.text = "00:00"
-            binding.tvDurationTips.text = getCompatString(R.string.profile_edit_talent_voice_record)
-            binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
+        recordTimer?.cancel()
+        recordTimer = null
+        recordTimes = 0
+        binding.tvDuration.text = "00:00"
+        binding.tvDurationTips.text = getCompatString(R.string.profile_edit_talent_voice_record)
+        binding.btnRecord.setImageResource(APP_R.drawable.profile_edit_talent_voice_record_ic)
+    }
+
+
+    private fun onPreviewStart() {
+        isPreviewPause = false
+        previewTimes = editViewModel.getRecordDuration()
+        if (previewTimer == null) {
+            previewTimer = Timer()
+        }
+        previewTimer?.schedule(object : TimerTask() {
+            override fun run() {
+                runOnUiThread {
+                    if (isPreviewPause) {
+                        return@runOnUiThread
+                    }
+                    previewTimes = max(previewTimes - 1, 0)
+                    if (isViewBindingValid()) {
+                        binding.tvPreviewDuration.text = formatMissTime(previewTimes)
+                    }
+                }
+            }
+        }, 0, 1000)
+
+        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_pause_ic)
+        binding.btnPreview.onClick {
+            pausePreview()
+        }
+    }
+
+    private fun pausePreview() {
+        isPreviewPause = true
+        AudioPlayer.getInstance().pausePlay()
+        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_ic)
+        binding.btnPreview.onClick {
+            resumePreview()
+        }
+    }
+
+    private fun resumePreview() {
+        isPreviewPause = false
+        AudioPlayer.getInstance().resumePlay()
+        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_pause_ic)
+        binding.btnPreview.onClick {
+            pausePreview()
+        }
+    }
+
+    @SuppressLint("SetTextI18n")
+    private fun resetPreview() {
+        isPreviewPause = false
+        previewTimer?.cancel()
+        previewTimer = null
+        previewTimes = 0
+        binding.tvPreviewDuration.text = formatMissTime(editViewModel.getRecordDuration())
+        binding.btnPreview.setImageResource(APP_R.drawable.profile_edit_talent_voice_preview_ic)
+        binding.btnPreview.onClick {
+            audioPreview()
         }
     }
 
@@ -261,8 +357,13 @@ class VoiceEditFragment : BaseFragment(R.layout.fragment_talent_voice_edit) {
 
     override fun onDestroyView() {
         super.onDestroyView()
-        AudioPlayer.getInstance().stopPlay()
+        recordTimer?.cancel()
+        recordTimer = null
         AudioRecorder.stopRecord()
+
+        previewTimer?.cancel()
+        previewTimer = null
+        AudioPlayer.getInstance().stopPlay()
     }
 
 }

+ 4 - 0
module/profile/src/main/java/com/adealink/weparty/profile/edit/dialog/viewmodel/EditVoiceViewModel.kt

@@ -78,6 +78,10 @@ class EditVoiceViewModel : BaseViewModel() {
         voiceDataLD.send(data)
     }
 
+    fun getRecordDuration(): Int{
+        return ((voiceData?.duration ?: 0) + 1000) / 1000
+    }
+
     fun submit(): LiveData<Rlt<Any>> {
         val liveData = OnceMutableLiveData<Rlt<Any>>()
         viewModelScope.launch {