when a voice message is played, starts the download of the next ones if any, computes their durations and starts playing the next one at the end of the current. Plays a doodle between them

Signed-off-by: Giacomo Pacini <giacomopacini98@gmail.com>
This commit is contained in:
Giacomo Pacini 2024-12-15 23:56:47 +01:00
parent 410b27b72c
commit 6a598357fc
No known key found for this signature in database
GPG Key ID: 2FBC97406B43D889
4 changed files with 75 additions and 3 deletions

View File

@ -185,6 +185,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
} }
private fun handleIsPlayingVoiceMessageState(message: ChatMessage) { private fun handleIsPlayingVoiceMessageState(message: ChatMessage) {
colorizeMessageBubble(message)
if (message.isPlayingVoiceMessage) { if (message.isPlayingVoiceMessage) {
showPlayButton() showPlayButton()
binding.playPauseBtn.icon = ContextCompat.getDrawable( binding.playPauseBtn.icon = ContextCompat.getDrawable(
@ -199,6 +200,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
binding.seekbar.max = message.voiceMessageDuration * ONE_SEC binding.seekbar.max = message.voiceMessageDuration * ONE_SEC
binding.seekbar.progress = message.voiceMessageSeekbarProgress binding.seekbar.progress = message.voiceMessageSeekbarProgress
} else { } else {
showVoiceMessageDuration(message)
binding.playPauseBtn.visibility = View.VISIBLE binding.playPauseBtn.visibility = View.VISIBLE
binding.playPauseBtn.icon = ContextCompat.getDrawable( binding.playPauseBtn.icon = ContextCompat.getDrawable(
context!!, context!!,

View File

@ -219,6 +219,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
} }
private fun handleIsPlayingVoiceMessageState(message: ChatMessage) { private fun handleIsPlayingVoiceMessageState(message: ChatMessage) {
colorizeMessageBubble(message)
if (message.isPlayingVoiceMessage) { if (message.isPlayingVoiceMessage) {
showPlayButton() showPlayButton()
binding.playPauseBtn.icon = ContextCompat.getDrawable( binding.playPauseBtn.icon = ContextCompat.getDrawable(
@ -233,6 +234,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
binding.seekbar.max = message.voiceMessageDuration * ONE_SEC binding.seekbar.max = message.voiceMessageDuration * ONE_SEC
binding.seekbar.progress = message.voiceMessageSeekbarProgress binding.seekbar.progress = message.voiceMessageSeekbarProgress
} else { } else {
showVoiceMessageDuration(message)
binding.playPauseBtn.visibility = View.VISIBLE binding.playPauseBtn.visibility = View.VISIBLE
binding.playPauseBtn.icon = ContextCompat.getDrawable( binding.playPauseBtn.icon = ContextCompat.getDrawable(
context!!, context!!,

View File

@ -27,6 +27,11 @@ import android.database.Cursor
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.media.AudioFocusRequest
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord
import android.media.MediaMetadataRetriever
import android.media.MediaPlayer import android.media.MediaPlayer
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -1614,16 +1619,70 @@ class ChatActivity :
} }
private fun startPlayback(message: ChatMessage, doPlay: Boolean = true) { private fun startPlayback(message: ChatMessage, doPlay: Boolean = true) {
if (!active) { //if (!active) {
// don't begin to play voice message if screen is not visible anymore. // don't begin to play voice message if screen is not visible anymore.
// this situation might happen if file is downloading but user already left the chatview. // this situation might happen if file is downloading but user already left the chatview.
// If user returns to chatview, the old chatview instance is not attached anymore // If user returns to chatview, the old chatview instance is not attached anymore
// and he has to click the play button again (which is considered to be okay) // and he has to click the play button again (which is considered to be okay)
return // return
} //}
initMediaPlayer(message) initMediaPlayer(message)
val id = message.id.toString()
val index = adapter?.getMessagePositionById(id) ?: 0
var nextMessage : ChatMessage? = null
for (i in 1..5) {
if(index - i < 0){
break
}
val curMsg = adapter?.items?.get(index - i)?.item
if(curMsg is ChatMessage) {
if(nextMessage == null) {
nextMessage = curMsg as ChatMessage
}
if(curMsg.isVoiceMessage){
val filename = curMsg.selectedIndividualHashMap!!["name"]
val file = File(context.cacheDir, filename!!)
if (!file.exists()) {
downloadFileToCache(curMsg as ChatMessage, false) {
curMsg.isDownloadingVoiceMessage = false
curMsg.voiceMessageDuration = try {
val retriever = MediaMetadataRetriever()
retriever.setDataSource(file.absolutePath) // Set the audio file as the data source
val durationStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
retriever.release() // Always release the retriever to free resources
(durationStr?.toIntOrNull() ?: 0 )/ 1000 // Convert to int (seconds)
} catch (e: Exception) {
e.printStackTrace()
0
}
adapter?.update(curMsg)
}
}else{
if(curMsg.voiceMessageDuration == 0) {
curMsg.voiceMessageDuration = try {
val retriever = MediaMetadataRetriever()
retriever.setDataSource(file.absolutePath) // Set the audio file as the data source
val durationStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
retriever.release() // Always release the retriever to free resources
(durationStr?.toIntOrNull() ?: 0 )/ 1000 // Convert to int (seconds)
} catch (e: Exception) {
e.printStackTrace()
0
}
adapter?.update(curMsg)
}
}
}
}
}
val hasConsecutiveVoiceMessage = if(nextMessage != null) nextMessage.isVoiceMessage else false
mediaPlayer?.let { mediaPlayer?.let {
if (!it.isPlaying && doPlay) { if (!it.isPlaying && doPlay) {
chatViewModel.audioRequest(true) { chatViewModel.audioRequest(true) {
@ -1656,6 +1715,15 @@ class ChatActivity :
message.voiceMessageSeekbarProgress = 0 message.voiceMessageSeekbarProgress = 0
adapter?.update(message) adapter?.update(message)
stopMediaPlayer(message) stopMediaPlayer(message)
if(hasConsecutiveVoiceMessage){
val defaultMediaPlayer = MediaPlayer.create(context, R.raw
.next_voice_message_doodle)
defaultMediaPlayer.setOnCompletionListener {
defaultMediaPlayer.release()
setUpWaveform(nextMessage as ChatMessage, doPlay)
}
defaultMediaPlayer.start()
}
} }
} }
} }

Binary file not shown.