录音取消逻辑

This commit is contained in:
renhaoting 2025-10-27 14:28:46 +08:00
parent 75ab00be93
commit 103a91e7c1
4 changed files with 66 additions and 53 deletions

View File

@ -1,6 +1,7 @@
package com.remax.visualnovel.ui.chat
import android.graphics.Point
import androidx.activity.viewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
@ -25,7 +26,6 @@ import com.remax.visualnovel.extension.toast
import com.remax.visualnovel.manager.nim.NimManager
import com.remax.visualnovel.ui.chat.setting.model.ChatModelDialog
import com.remax.visualnovel.ui.chat.ui.HoldToTalkDialog
import com.remax.visualnovel.ui.wallet.manager.WalletManager
import com.remax.visualnovel.utils.RecordHelper
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Job
@ -90,13 +90,20 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
private fun initInputPanelEvents() {
with(binding.inputPanel) {
holdToTalk({
holdToTalk(
{
mRecordAssist.startRecording()
}) {
},
{
mRecordAssist.stopTalk()
},
touchPosCallback = { point ->
mRecordAssist.onTouchPointChanged(point)
}
)
}
}
}
/**
* 检查麦克风权限
@ -179,6 +186,7 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
inner class RecordAssist {
private var mIsCancelled = false
private var recordJob: Job? = null
private val recordHelper by lazy {
@ -210,8 +218,8 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
private fun startTalk() {
val maxTalkTime = 60
val minTalkTime = 1
var recordingProgress = 0
mIsCancelled = false
holdToTalkDialog.show()
recordHelper.startRecording(this@ChatActivity, {
@ -223,6 +231,7 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
})
}, {
if (!mIsCancelled) {
if (recordingProgress >= minTalkTime) {
Timber.i("startRecording onStop: ${recordHelper.getFilename()}")
@ -237,19 +246,26 @@ class ChatActivity : BaseBindingActivity<ActivityActorChatBinding>() {
}
} else {
//录音最少1秒
showToast(R.string.min_voice_time)
showToast(R.string.min_voice_time) //录音最少1秒
}
}
})
}
fun stopTalk() {
mIsCancelled = holdToTalkDialog.isTouchInCancelArea;
holdToTalkDialog.dismiss()
recordJob?.cancel()
recordHelper.stopRecording()
}
fun onTouchPointChanged(point: Point) {
if (holdToTalkDialog.isShowing) {
holdToTalkDialog.onTouchPointChanged(point)
}
}
}
}

View File

@ -2,6 +2,7 @@ package com.remax.visualnovel.ui.chat
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Point
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout
@ -82,7 +83,7 @@ class InputPanel @JvmOverloads constructor(context: Context, attrs: AttributeSet
@SuppressLint("ClickableViewAccessibility")
fun holdToTalk(callback: () -> Unit, cancelCallback: () -> Unit) {
fun holdToTalk(callback: () -> Unit, cancelCallback: () -> Unit, touchPosCallback: (point: Point) -> Unit) {
binding.ivHold2talk.run {
setOnTouchListener { v, event ->
when (event.action) {
@ -93,10 +94,15 @@ class InputPanel @JvmOverloads constructor(context: Context, attrs: AttributeSet
MotionEvent.ACTION_UP -> {
cancelCallback.invoke()
}
MotionEvent.ACTION_MOVE -> {
touchPosCallback.invoke(Point(event.rawX.toInt(), event.rawY.toInt()))
}
}
true
}
}
}
}

View File

@ -1,68 +1,58 @@
package com.remax.visualnovel.ui.chat.ui
import android.content.Context
import android.graphics.Point
import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.core.view.isVisible
import com.remax.visualnovel.R
import com.remax.visualnovel.databinding.DialogHoldToTalkBinding
import com.remax.visualnovel.widget.dialoglib.LBindingDialog
/**
* Created by HJW on 2025/8/16
*/
class HoldToTalkDialog(context: Context) :
LBindingDialog<DialogHoldToTalkBinding>(context, DialogHoldToTalkBinding::inflate) {
var isTouchInCancelArea = false
fun build(): HoldToTalkDialog {
with()
setBottom()
setBgColorToken(R.string.color_transparent)
setMaskValue(0f)
initRootTouchEvent()
show()
return this
}
private fun initRootTouchEvent() {
with(binding.root) {
fun onTouchEvent(event: MotionEvent): Boolean {
val x = event.x.toInt()
val y = event.y.toInt()
when (event.actionMasked) {
MotionEvent.ACTION_MOVE -> {
updateStateUI(event)
}
}
return false
}
}
}
private fun isInValidArea(event: MotionEvent) : Boolean {
val rect = Rect()
binding.viewRelease.getHitRect(rect)
return rect.contains(event.rawX.toInt(), event.rawY.toInt())
}
private fun updateStateUI(event: MotionEvent) {
fun onTouchPointChanged(point: Point) {
with (binding) {
when (isInValidArea(event)) {
true -> {
isTouchInCancelArea = !getTouchValidArea().contains(point.x, point.y)
when (isTouchInCancelArea) {
false -> {
viewRelease.setBackgroundResource(R.mipmap.bg_recording_normal)
cancelHintRoot.isVisible = true
tvRelease.text = context.resources.getString(R.string.release_to_send)
}
false -> {
true -> {
viewRelease.setBackgroundResource(R.mipmap.bg_recording_cancel)
cancelHintRoot.isVisible = false
tvRelease.text = context.resources.getString(R.string.release_to_cancel)
}
}
}
}
private fun getTouchValidArea(): Rect {
val location = IntArray(2)
binding.viewRelease.getLocationOnScreen(location)
return Rect(
location[0],
location[1],
location[0] + binding.viewRelease.width,
location[1] + binding.viewRelease.height
)
}
}

View File

@ -337,7 +337,7 @@
<string name="prompt">Prompt</string>
<string name="heart_member_unlock">Heart member unlock</string>
<string name="member_unlock">Member unlock</string>
<string name="release_to_send">Release to send</string>
<string name="my_chat_personal">My Chat Personal</string>
<string name="chat_setting">Chat Setting</string>
<string name="auto_play_voice">Auto play voice</string>
@ -466,6 +466,7 @@
<string name="hold_to_talk">Hold to Talk</string>
<string name="type_msg_hint">Type a message</string>
<string name="swipe_up_to_cancel">Swipe Up to Cancel</string>
<string name="release_to_send">Release to Send</string>
<string name="release_to_cancel">Release to Cancel</string>
</resources>