From d47deb42c8bbfaea97a64c8ba8a39ff44444ba15 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 28 Jun 2021 14:39:29 +0200 Subject: [PATCH 01/16] move mediaPlayer and download-logic for voicemessages to ChatController Signed-off-by: Marcel Hibbe --- .../IncomingVoiceMessageViewHolder.kt | 234 ++++----------- .../OutcomingVoiceMessageViewHolder.kt | 273 ++++++------------ .../messages/TalkMessagesListAdapter.java | 24 +- .../messages/VoiceMessageInterface.kt | 7 + .../talk/controllers/ChatController.kt | 179 +++++++++++- .../talk/models/json/chat/ChatMessage.java | 20 +- .../item_custom_incoming_voice_message.xml | 14 +- .../item_custom_outcoming_voice_message.xml | 15 +- 8 files changed, 377 insertions(+), 389 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 8e1a65b38..ae4820d62 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -29,19 +29,14 @@ import android.app.Activity import android.content.Context import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable -import android.media.MediaPlayer -import android.os.Handler import android.text.TextUtils import android.util.Log import android.view.View import android.widget.SeekBar -import android.widget.SeekBar.OnSeekBarChangeListener import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.view.ViewCompat -import androidx.work.Data -import androidx.work.OneTimeWorkRequest import androidx.work.WorkInfo import androidx.work.WorkManager import autodagger.AutoInjector @@ -51,14 +46,11 @@ import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.databinding.ItemCustomIncomingVoiceMessageBinding -import com.nextcloud.talk.jobs.DownloadFileToCacheWorker -import com.nextcloud.talk.models.database.CapabilitiesUtil import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.preferences.AppPreferences import com.stfalcon.chatkit.messages.MessageHolders -import java.io.File import java.util.concurrent.ExecutionException import javax.inject.Inject @@ -81,9 +73,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders lateinit var activity: Activity - var mediaPlayer: MediaPlayer? = null - - lateinit var handler: Handler + lateinit var voiceMessageInterface: VoiceMessageInterface @SuppressLint("SetTextI18n") override fun onBind(message: ChatMessage) { @@ -101,47 +91,94 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders // parent message handling setParentMessageDataOnMessageItem(message) - binding.playBtn.setOnClickListener { - openOrDownloadFile(message) + + updateDownloadState(message) + binding.seekbar.max = message.voiceMessageDuration + + if (message.isPlayingVoiceMessage) { + binding.progressBar.visibility = View.GONE + binding.playPauseBtn.visibility = View.VISIBLE + binding.playPauseBtn.icon = + ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_pause_voice_message_24) + binding.seekbar.progress = message.voiceMessagePlayedSeconds + } else { + binding.playPauseBtn.visibility = View.VISIBLE + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, R.drawable + .ic_baseline_play_arrow_voice_message_24 + ) } - binding.pauseBtn.setOnClickListener { - pausePlayback() + if (message.isDownloadingVoiceMessage) { + binding.playPauseBtn.visibility = View.GONE + binding.progressBar.visibility = View.VISIBLE + } else { + binding.progressBar.visibility = View.GONE + } + + if (message.resetVoiceMessage) { + binding.playPauseBtn.visibility = View.VISIBLE + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, R.drawable + .ic_baseline_play_arrow_voice_message_24 + ) + binding.seekbar.progress = SEEKBAR_START + message.resetVoiceMessage = false } activity = itemView.context as Activity - binding.seekbar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { + + binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onStopTrackingTouch(seekBar: SeekBar) { // unused atm } + override fun onStartTrackingTouch(seekBar: SeekBar) { // unused atm } + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { - if (mediaPlayer != null && fromUser) { - mediaPlayer!!.seekTo(progress * SEEKBAR_BASE) + if (fromUser) { + voiceMessageInterface.updateMediaPlayerProgressBySlider(message, progress) } } }) + } + private fun updateDownloadState(message: ChatMessage) { // check if download worker is already running val fileId = message.getSelectedIndividualHashMap()["id"] - val workers = WorkManager.getInstance( - context!! - ).getWorkInfosByTag(fileId!!) + val workers = WorkManager.getInstance(context!!).getWorkInfosByTag(fileId!!) try { for (workInfo in workers.get()) { if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { binding.progressBar.visibility = View.VISIBLE - binding.playBtn.visibility = View.GONE + binding.playPauseBtn.visibility = View.GONE WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(workInfo.id) .observeForever { info: WorkInfo? -> if (info != null) { - updateViewsByProgress( - info - ) + + when (info.state) { + WorkInfo.State.RUNNING -> { + Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder") + binding.playPauseBtn.visibility = View.GONE + binding.progressBar.visibility = View.VISIBLE + } + WorkInfo.State.SUCCEEDED -> { + Log.d(TAG, "WorkInfo.State.SUCCEEDED in ViewHolder") + binding.playPauseBtn.visibility = View.VISIBLE + binding.progressBar.visibility = View.GONE + } + WorkInfo.State.FAILED -> { + Log.d(TAG, "WorkInfo.State.FAILED in ViewHolder") + binding.playPauseBtn.visibility = View.VISIBLE + binding.progressBar.visibility = View.GONE + } + else -> { + } + } } } } @@ -249,155 +286,12 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders } } - private fun openOrDownloadFile(message: ChatMessage) { - val filename = message.getSelectedIndividualHashMap()["name"] - val file = File(context!!.cacheDir, filename!!) - if (file.exists()) { - binding.progressBar.visibility = View.GONE - startPlayback(message) - } else { - binding.playBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE - downloadFileToCache(message) - } - } - - private fun startPlayback(message: ChatMessage) { - initMediaPlayer(message) - - if (!mediaPlayer!!.isPlaying) { - mediaPlayer!!.start() - } - - handler = Handler() - activity.runOnUiThread(object : Runnable { - override fun run() { - if (mediaPlayer != null) { - val currentPosition: Int = mediaPlayer!!.currentPosition / SEEKBAR_BASE - binding.seekbar.progress = currentPosition - } - handler.postDelayed(this, SECOND) - } - }) - - binding.progressBar.visibility = View.GONE - binding.playBtn.visibility = View.GONE - binding.pauseBtn.visibility = View.VISIBLE - } - - private fun pausePlayback() { - if (mediaPlayer!!.isPlaying) { - mediaPlayer!!.pause() - } - - binding.playBtn.visibility = View.VISIBLE - binding.pauseBtn.visibility = View.GONE - } - - private fun initMediaPlayer(message: ChatMessage) { - val fileName = message.getSelectedIndividualHashMap()["name"] - val absolutePath = context!!.cacheDir.absolutePath + "/" + fileName - - if (mediaPlayer == null) { - mediaPlayer = MediaPlayer().apply { - setDataSource(absolutePath) - prepare() - } - } - - binding.seekbar.max = mediaPlayer!!.duration / SEEKBAR_BASE - - mediaPlayer!!.setOnCompletionListener { - binding.playBtn.visibility = View.VISIBLE - binding.pauseBtn.visibility = View.GONE - binding.seekbar.progress = SEEKBAR_START - handler.removeCallbacksAndMessages(null) - mediaPlayer?.stop() - mediaPlayer?.release() - mediaPlayer = null - } - } - - @SuppressLint("LongLogTag") - private fun downloadFileToCache(message: ChatMessage) { - val baseUrl = message.activeUser.baseUrl - val userId = message.activeUser.userId - val attachmentFolder = CapabilitiesUtil.getAttachmentFolder(message.activeUser) - val fileName = message.getSelectedIndividualHashMap()["name"] - var size = message.getSelectedIndividualHashMap()["size"] - if (size == null) { - size = "-1" - } - val fileSize = Integer.valueOf(size) - val fileId = message.getSelectedIndividualHashMap()["id"] - val path = message.getSelectedIndividualHashMap()["path"] - - // check if download worker is already running - val workers = WorkManager.getInstance( - context!! - ).getWorkInfosByTag(fileId!!) - try { - for (workInfo in workers.get()) { - if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { - Log.d(TAG, "Download worker for " + fileId + " is already running or scheduled") - return - } - } - } catch (e: ExecutionException) { - Log.e(TAG, "Error when checking if worker already exists", e) - } catch (e: InterruptedException) { - Log.e(TAG, "Error when checking if worker already exists", e) - } - - val data: Data = Data.Builder() - .putString(DownloadFileToCacheWorker.KEY_BASE_URL, baseUrl) - .putString(DownloadFileToCacheWorker.KEY_USER_ID, userId) - .putString(DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, attachmentFolder) - .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileName) - .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) - .putInt(DownloadFileToCacheWorker.KEY_FILE_SIZE, fileSize) - .build() - - val downloadWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(DownloadFileToCacheWorker::class.java) - .setInputData(data) - .addTag(fileId) - .build() - - WorkManager.getInstance().enqueue(downloadWorker) - - WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(downloadWorker.id) - .observeForever { workInfo: WorkInfo -> - updateViewsByProgress( - workInfo - ) - } - } - - private fun updateViewsByProgress(workInfo: WorkInfo) { - when (workInfo.state) { - WorkInfo.State.RUNNING -> { - val progress = workInfo.progress.getInt(DownloadFileToCacheWorker.PROGRESS, -1) - if (progress > -1) { - binding.playBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE - } - } - WorkInfo.State.SUCCEEDED -> { - startPlayback(message) - } - WorkInfo.State.FAILED -> { - binding.progressBar.visibility = View.GONE - binding.playBtn.visibility = View.VISIBLE - } - else -> { - } - } + fun assignAdapter(voiceMessageInterface: VoiceMessageInterface) { + this.voiceMessageInterface = voiceMessageInterface } companion object { private const val TAG = "VoiceInMessageView" - private const val SECOND: Long = 1000 - private const val SEEKBAR_BASE: Int = 1000 private const val SEEKBAR_START: Int = 0 } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index 7b8437ce4..ef574968d 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -27,15 +27,13 @@ import android.app.Activity import android.content.Context import android.graphics.PorterDuff import android.media.MediaPlayer -import android.net.Uri import android.os.Handler import android.util.Log import android.view.View import android.widget.SeekBar import androidx.appcompat.content.res.AppCompatResources +import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat -import androidx.work.Data -import androidx.work.OneTimeWorkRequest import androidx.work.WorkInfo import androidx.work.WorkManager import autodagger.AutoInjector @@ -44,21 +42,18 @@ import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.databinding.ItemCustomOutcomingVoiceMessageBinding -import com.nextcloud.talk.jobs.DownloadFileToCacheWorker -import com.nextcloud.talk.models.database.CapabilitiesUtil import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ReadStatus import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.preferences.AppPreferences import com.stfalcon.chatkit.messages.MessageHolders -import java.io.File import java.util.concurrent.ExecutionException import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class OutcomingVoiceMessageViewHolder(incomingView: View) : MessageHolders -.OutcomingTextMessageViewHolder(incomingView) { +class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders +.OutcomingTextMessageViewHolder(outcomingView) { private val binding: ItemCustomOutcomingVoiceMessageBinding = ItemCustomOutcomingVoiceMessageBinding.bind(itemView) @@ -80,6 +75,8 @@ class OutcomingVoiceMessageViewHolder(incomingView: View) : MessageHolders lateinit var handler: Handler + lateinit var voiceMessageInterface: VoiceMessageInterface + @SuppressLint("SetTextI18n") override fun onBind(message: ChatMessage) { super.onBind(message) @@ -94,57 +91,59 @@ class OutcomingVoiceMessageViewHolder(incomingView: View) : MessageHolders // parent message handling setParentMessageDataOnMessageItem(message) - binding.playBtn.setOnClickListener { - openOrDownloadFile(message) + updateDownloadState(message) + binding.seekbar.max = message.voiceMessageDuration + + if (message.isPlayingVoiceMessage) { + binding.progressBar.visibility = View.GONE + binding.playPauseBtn.visibility = View.VISIBLE + binding.playPauseBtn.icon = + ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_pause_voice_message_24) + binding.seekbar.progress = message.voiceMessagePlayedSeconds + } else { + binding.playPauseBtn.visibility = View.VISIBLE + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, R.drawable + .ic_baseline_play_arrow_voice_message_24 + ) } - binding.pauseBtn.setOnClickListener { - pausePlayback() + if (message.isDownloadingVoiceMessage) { + binding.playPauseBtn.visibility = View.GONE + binding.progressBar.visibility = View.VISIBLE + } else { + binding.progressBar.visibility = View.GONE + } + + if (message.resetVoiceMessage) { + binding.playPauseBtn.visibility = View.VISIBLE + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, R.drawable + .ic_baseline_play_arrow_voice_message_24 + ) + binding.seekbar.progress = SEEKBAR_START + message.resetVoiceMessage = false } activity = itemView.context as Activity + binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onStopTrackingTouch(seekBar: SeekBar) { // unused atm } + override fun onStartTrackingTouch(seekBar: SeekBar) { // unused atm } + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { - if (mediaPlayer != null && fromUser) { - mediaPlayer!!.seekTo(progress * SEEKBAR_BASE) + if (fromUser) { + voiceMessageInterface.updateMediaPlayerProgressBySlider(message, progress) } } }) - // check if download worker is already running - val fileId = message.getSelectedIndividualHashMap()["id"] - val workers = WorkManager.getInstance( - context!! - ).getWorkInfosByTag(fileId!!) - - try { - for (workInfo in workers.get()) { - if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { - binding.progressBar.visibility = View.VISIBLE - binding.playBtn.visibility = View.GONE - WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(workInfo.id) - .observeForever { info: WorkInfo? -> - if (info != null) { - updateViewsByProgress( - info - ) - } - } - } - } - } catch (e: ExecutionException) { - Log.e(TAG, "Error when checking if worker already exists", e) - } catch (e: InterruptedException) { - Log.e(TAG, "Error when checking if worker already exists", e) - } - val readStatusDrawableInt = when (message.readStatus) { ReadStatus.READ -> R.drawable.ic_check_all ReadStatus.SENT -> R.drawable.ic_check @@ -167,6 +166,50 @@ class OutcomingVoiceMessageViewHolder(incomingView: View) : MessageHolders binding.checkMark.setContentDescription(readStatusContentDescriptionString) } + private fun updateDownloadState(message: ChatMessage) { + // check if download worker is already running + val fileId = message.getSelectedIndividualHashMap()["id"] + val workers = WorkManager.getInstance(context!!).getWorkInfosByTag(fileId!!) + + try { + for (workInfo in workers.get()) { + if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { + binding.progressBar.visibility = View.VISIBLE + binding.playPauseBtn.visibility = View.GONE + WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(workInfo.id) + .observeForever { info: WorkInfo? -> + if (info != null) { + + when (info.state) { + WorkInfo.State.RUNNING -> { + Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder") + binding.playPauseBtn.visibility = View.GONE + binding.progressBar.visibility = View.VISIBLE + } + WorkInfo.State.SUCCEEDED -> { + Log.d(TAG, "WorkInfo.State.SUCCEEDED in ViewHolder") + binding.playPauseBtn.visibility = View.VISIBLE + binding.progressBar.visibility = View.GONE + } + WorkInfo.State.FAILED -> { + Log.d(TAG, "WorkInfo.State.FAILED in ViewHolder") + binding.playPauseBtn.visibility = View.VISIBLE + binding.progressBar.visibility = View.GONE + } + else -> { + } + } + } + } + } + } + } catch (e: ExecutionException) { + Log.e(TAG, "Error when checking if worker already exists", e) + } catch (e: InterruptedException) { + Log.e(TAG, "Error when checking if worker already exists", e) + } + } + private fun setParentMessageDataOnMessageItem(message: ChatMessage) { if (!message.isDeleted && message.parentMessage != null) { val parentChatMessage = message.parentMessage @@ -224,156 +267,12 @@ class OutcomingVoiceMessageViewHolder(incomingView: View) : MessageHolders } } - private fun openOrDownloadFile(message: ChatMessage) { - val filename = message.getSelectedIndividualHashMap()["name"] - val file = File(context!!.cacheDir, filename!!) - - if (file.exists()) { - binding.progressBar.visibility = View.GONE - startPlayback(message) - } else { - binding.playBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE - downloadFileToCache(message) - } - } - - private fun startPlayback(message: ChatMessage) { - initMediaPlayer(message) - - if (!mediaPlayer!!.isPlaying) { - mediaPlayer!!.start() - } - - handler = Handler() - activity.runOnUiThread(object : Runnable { - override fun run() { - if (mediaPlayer != null) { - val currentPosition: Int = mediaPlayer!!.currentPosition / SEEKBAR_BASE - binding.seekbar.progress = currentPosition - } - handler.postDelayed(this, SECOND) - } - }) - - binding.progressBar.visibility = View.GONE - binding.playBtn.visibility = View.GONE - binding.pauseBtn.visibility = View.VISIBLE - } - - private fun pausePlayback() { - if (mediaPlayer!!.isPlaying) { - mediaPlayer!!.pause() - } - - binding.playBtn.visibility = View.VISIBLE - binding.pauseBtn.visibility = View.GONE - } - - private fun initMediaPlayer(message: ChatMessage) { - val fileName = message.getSelectedIndividualHashMap()["name"] - val absolutePath = context!!.cacheDir.absolutePath + "/" + fileName - - if (mediaPlayer == null) { - mediaPlayer = MediaPlayer().apply { - setDataSource(context!!, Uri.parse(absolutePath)) - prepare() - } - } - - binding.seekbar.max = mediaPlayer!!.duration / SEEKBAR_BASE - - mediaPlayer!!.setOnCompletionListener { - binding.playBtn.visibility = View.VISIBLE - binding.pauseBtn.visibility = View.GONE - binding.seekbar.progress = SEEKBAR_START - handler.removeCallbacksAndMessages(null) - mediaPlayer?.stop() - mediaPlayer?.release() - mediaPlayer = null - } - } - - @SuppressLint("LongLogTag") - private fun downloadFileToCache(message: ChatMessage) { - val baseUrl = message.activeUser.baseUrl - val userId = message.activeUser.userId - val attachmentFolder = CapabilitiesUtil.getAttachmentFolder(message.activeUser) - val fileName = message.getSelectedIndividualHashMap()["name"] - var size = message.getSelectedIndividualHashMap()["size"] - if (size == null) { - size = "-1" - } - val fileSize = Integer.valueOf(size) - val fileId = message.getSelectedIndividualHashMap()["id"] - val path = message.getSelectedIndividualHashMap()["path"] - - // check if download worker is already running - val workers = WorkManager.getInstance( - context!! - ).getWorkInfosByTag(fileId!!) - try { - for (workInfo in workers.get()) { - if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { - Log.d(TAG, "Download worker for " + fileId + " is already running or scheduled") - return - } - } - } catch (e: ExecutionException) { - Log.e(TAG, "Error when checking if worker already exists", e) - } catch (e: InterruptedException) { - Log.e(TAG, "Error when checking if worker already exists", e) - } - - val data: Data = Data.Builder() - .putString(DownloadFileToCacheWorker.KEY_BASE_URL, baseUrl) - .putString(DownloadFileToCacheWorker.KEY_USER_ID, userId) - .putString(DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, attachmentFolder) - .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileName) - .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) - .putInt(DownloadFileToCacheWorker.KEY_FILE_SIZE, fileSize) - .build() - - val downloadWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(DownloadFileToCacheWorker::class.java) - .setInputData(data) - .addTag(fileId) - .build() - - WorkManager.getInstance().enqueue(downloadWorker) - - WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(downloadWorker.id) - .observeForever { workInfo: WorkInfo -> - updateViewsByProgress( - workInfo - ) - } - } - - private fun updateViewsByProgress(workInfo: WorkInfo) { - when (workInfo.state) { - WorkInfo.State.RUNNING -> { - val progress = workInfo.progress.getInt(DownloadFileToCacheWorker.PROGRESS, -1) - if (progress > -1) { - binding.playBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE - } - } - WorkInfo.State.SUCCEEDED -> { - startPlayback(message) - } - WorkInfo.State.FAILED -> { - binding.progressBar.visibility = View.GONE - binding.playBtn.visibility = View.VISIBLE - } - else -> { - } - } + fun assignAdapter(voiceMessageInterface: VoiceMessageInterface) { + this.voiceMessageInterface = voiceMessageInterface } companion object { private const val TAG = "VoiceOutMessageView" - private const val SECOND: Long = 1000 - private const val SEEKBAR_BASE: Int = 1000 private const val SEEKBAR_START: Int = 0 } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java index bcf6e92ee..859276eee 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java @@ -20,7 +20,9 @@ package com.nextcloud.talk.adapters.messages; +import com.nextcloud.talk.controllers.ChatController; import com.stfalcon.chatkit.commons.ImageLoader; +import com.stfalcon.chatkit.commons.ViewHolder; import com.stfalcon.chatkit.commons.models.IMessage; import com.stfalcon.chatkit.messages.MessageHolders; import com.stfalcon.chatkit.messages.MessagesListAdapter; @@ -28,12 +30,32 @@ import com.stfalcon.chatkit.messages.MessagesListAdapter; import java.util.List; public class TalkMessagesListAdapter extends MessagesListAdapter { + private final ChatController chatController; - public TalkMessagesListAdapter(String senderId, MessageHolders holders, ImageLoader imageLoader) { + public TalkMessagesListAdapter( + String senderId, + MessageHolders holders, + ImageLoader imageLoader, + ChatController chatController) { super(senderId, holders, imageLoader); + this.chatController = chatController; } public List getItems() { return items; } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + super.onBindViewHolder(holder, position); + + if (holder instanceof IncomingVoiceMessageViewHolder) { + ((IncomingVoiceMessageViewHolder) holder).assignAdapter(chatController); + } + + if (holder instanceof OutcomingVoiceMessageViewHolder) { + ((OutcomingVoiceMessageViewHolder) holder).assignAdapter(chatController); + } + + } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt new file mode 100644 index 000000000..4f4745cca --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt @@ -0,0 +1,7 @@ +package com.nextcloud.talk.adapters.messages + +import com.nextcloud.talk.models.json.chat.ChatMessage + +interface VoiceMessageInterface { + fun updateMediaPlayerProgressBySlider(message : ChatMessage, progress : Int) +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index 44484197d..0cb36d569 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -34,6 +34,7 @@ import android.content.pm.PackageManager import android.content.res.Resources import android.graphics.Bitmap import android.graphics.drawable.ColorDrawable +import android.media.MediaPlayer import android.media.MediaRecorder import android.net.Uri import android.os.Build @@ -76,6 +77,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.work.Data import androidx.work.OneTimeWorkRequest +import androidx.work.WorkInfo import androidx.work.WorkManager import autodagger.AutoInjector import coil.load @@ -102,6 +104,7 @@ import com.nextcloud.talk.adapters.messages.OutcomingLocationMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingPreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.OutcomingVoiceMessageViewHolder import com.nextcloud.talk.adapters.messages.TalkMessagesListAdapter +import com.nextcloud.talk.adapters.messages.VoiceMessageInterface import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.callbacks.MentionAutocompleteCallback @@ -112,6 +115,7 @@ import com.nextcloud.talk.controllers.util.viewBinding import com.nextcloud.talk.databinding.ControllerChatBinding import com.nextcloud.talk.events.UserMentionClickEvent import com.nextcloud.talk.events.WebSocketCommunicationEvent +import com.nextcloud.talk.jobs.DownloadFileToCacheWorker import com.nextcloud.talk.jobs.UploadAndShareFilesWorker import com.nextcloud.talk.models.database.CapabilitiesUtil import com.nextcloud.talk.models.database.UserEntity @@ -175,6 +179,7 @@ import java.util.ArrayList import java.util.Date import java.util.HashMap import java.util.Objects +import java.util.concurrent.ExecutionException import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -186,7 +191,8 @@ class ChatController(args: Bundle) : MessagesListAdapter.OnLoadMoreListener, MessagesListAdapter.Formatter, MessagesListAdapter.OnMessageViewLongClickListener, - ContentChecker { + ContentChecker, VoiceMessageInterface { + private val binding: ControllerChatBinding by viewBinding(ControllerChatBinding::bind) @Inject @@ -247,6 +253,10 @@ class ChatController(args: Bundle) : private var recorder: MediaRecorder? = null + var mediaPlayer: MediaPlayer? = null + lateinit var mediaPlayerHandler: Handler + var currentlyPlayedVoiceMessage: ChatMessage? = null + init { setHasOptionsMenu(true) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) @@ -488,7 +498,7 @@ class ChatController(args: Bundle) : .setAutoPlayAnimations(true) .build() imageView.controller = draweeController - } + }, this ) } else { binding.messagesListView.visibility = View.VISIBLE @@ -499,6 +509,22 @@ class ChatController(args: Bundle) : adapter?.setDateHeadersFormatter { format(it) } adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message) } + adapter?.registerViewClickListener( + R.id.playPauseBtn + ) { view, message -> + val filename = message.getSelectedIndividualHashMap()["name"] + val file = File(context!!.cacheDir, filename!!) + if (file.exists()) { + if (message.isPlayingVoiceMessage) { + pausePlayback(message) + } else { + startPlayback(message) + } + } else { + downloadFileToCache(message) + } + } + if (context != null) { val messageSwipeController = MessageSwipeCallback( activity!!, @@ -749,6 +775,151 @@ class ChatController(args: Bundle) : super.onViewBound(view) } + private fun startPlayback(message: ChatMessage) { + + if (!this.isAttached) { + // 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. + // 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) + return + } + + initMediaPlayer(message) + + if (!mediaPlayer!!.isPlaying) { + mediaPlayer!!.start() + } + + mediaPlayerHandler = Handler() + activity?.runOnUiThread(object : Runnable { + override fun run() { + if (mediaPlayer != null) { + val currentPosition: Int = mediaPlayer!!.currentPosition / VOICE_MESSAGE_SEEKBAR_BASE + message.voiceMessagePlayedSeconds = currentPosition + adapter?.update(message) + } + mediaPlayerHandler.postDelayed(this, SECOND) + } + }) + + message.isDownloadingVoiceMessage = false + message.isPlayingVoiceMessage = true + adapter?.update(message) + } + + private fun pausePlayback(message: ChatMessage) { + if (mediaPlayer!!.isPlaying) { + mediaPlayer!!.pause() + } + + message.isPlayingVoiceMessage = false + adapter?.update(message) + } + + private fun initMediaPlayer(message: ChatMessage) { + if (message != currentlyPlayedVoiceMessage) { + currentlyPlayedVoiceMessage?.let { stopMediaPlayer(it) } + } + + if (mediaPlayer == null) { + val fileName = message.getSelectedIndividualHashMap()["name"] + val absolutePath = context!!.cacheDir.absolutePath + "/" + fileName + mediaPlayer = MediaPlayer().apply { + setDataSource(absolutePath) + prepare() + } + currentlyPlayedVoiceMessage = message + message.voiceMessageDuration = mediaPlayer!!.duration / VOICE_MESSAGE_SEEKBAR_BASE + + mediaPlayer!!.setOnCompletionListener { + stopMediaPlayer(message) + } + } else { + Log.e(TAG, "mediaPlayer was not null. This should not happen!") + } + } + + private fun stopMediaPlayer(message: ChatMessage) { + message.isPlayingVoiceMessage = false + message.resetVoiceMessage = true + adapter?.update(message) + + currentlyPlayedVoiceMessage = null + + mediaPlayerHandler.removeCallbacksAndMessages(null) + + mediaPlayer?.stop() + mediaPlayer?.release() + mediaPlayer = null + } + + override fun updateMediaPlayerProgressBySlider(messageWithSlidedProgress: ChatMessage, progress: Int) { + if (mediaPlayer != null) { + if (messageWithSlidedProgress == currentlyPlayedVoiceMessage) { + mediaPlayer!!.seekTo(progress * VOICE_MESSAGE_SEEKBAR_BASE) + } + } + } + + @SuppressLint("LongLogTag") + private fun downloadFileToCache(message: ChatMessage) { + message.isDownloadingVoiceMessage = true + adapter?.update(message) + + val baseUrl = message.activeUser.baseUrl + val userId = message.activeUser.userId + val attachmentFolder = CapabilitiesUtil.getAttachmentFolder(message.activeUser) + val fileName = message.getSelectedIndividualHashMap()["name"] + var size = message.getSelectedIndividualHashMap()["size"] + if (size == null) { + size = "-1" + } + val fileSize = Integer.valueOf(size) + val fileId = message.getSelectedIndividualHashMap()["id"] + val path = message.getSelectedIndividualHashMap()["path"] + + // check if download worker is already running + val workers = WorkManager.getInstance( + context!! + ).getWorkInfosByTag(fileId!!) + try { + for (workInfo in workers.get()) { + if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { + Log.d(TAG, "Download worker for " + fileId + " is already running or scheduled") + return + } + } + } catch (e: ExecutionException) { + Log.e(TAG, "Error when checking if worker already exists", e) + } catch (e: InterruptedException) { + Log.e(TAG, "Error when checking if worker already exists", e) + } + + val data: Data = Data.Builder() + .putString(DownloadFileToCacheWorker.KEY_BASE_URL, baseUrl) + .putString(DownloadFileToCacheWorker.KEY_USER_ID, userId) + .putString(DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, attachmentFolder) + .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileName) + .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) + .putInt(DownloadFileToCacheWorker.KEY_FILE_SIZE, fileSize) + .build() + + val downloadWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(DownloadFileToCacheWorker::class.java) + .setInputData(data) + .addTag(fileId) + .build() + + WorkManager.getInstance().enqueue(downloadWorker) + + WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(downloadWorker.id) + .observeForever { workInfo: WorkInfo -> + if (workInfo.state == WorkInfo.State.SUCCEEDED) { + startPlayback(message) + } + } + } + @SuppressLint("SimpleDateFormat") private fun setVoiceRecordFileName() { val pattern = "yyyy-MM-dd HH-mm-ss" @@ -1265,6 +1436,8 @@ class ChatController(args: Bundle) : if (mentionAutocomplete != null && mentionAutocomplete!!.isPopupShowing) { mentionAutocomplete?.dismissPopup() } + + currentlyPlayedVoiceMessage?.let { stopMediaPlayer(it) } } override val title: String @@ -2345,5 +2518,7 @@ class ChatController(args: Bundle) : private const val SHORT_VIBRATE: Long = 20 private const val FULLY_OPAQUE_INT: Int = 255 private const val SEMI_TRANSPARENT_INT: Int = 99 + private const val VOICE_MESSAGE_SEEKBAR_BASE: Int = 1000 + private const val SECOND: Long = 1000 } } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java index e2ad6c17c..13023253c 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java @@ -90,6 +90,22 @@ public class ChatMessage implements MessageContentType, MessageContentType.Image @JsonField(name = "messageType") public String messageType; + + public boolean isDownloadingVoiceMessage; + public boolean resetVoiceMessage; + public boolean isPlayingVoiceMessage; + public int voiceMessageDuration; + public int voiceMessagePlayedSeconds; + public VoiceMessageDownloadState voiceMessageDownloadState; + public int voiceMessageDownloadProgress; + + public enum VoiceMessageDownloadState { + NOT_STARTED, + RUNNING, + SUCCEEDED, + FAILED + } + @JsonIgnore List messageTypesToIgnore = Arrays.asList( MessageType.REGULAR_TEXT_MESSAGE, @@ -100,6 +116,8 @@ public class ChatMessage implements MessageContentType, MessageContentType.Image MessageType.SINGLE_NC_GEOLOCATION_MESSAGE, MessageType.VOICE_MESSAGE); + + public boolean hasFileAttachment() { if (messageParameters != null && messageParameters.size() > 0) { for (HashMap.Entry> entry : messageParameters.entrySet()) { @@ -133,8 +151,6 @@ public class ChatMessage implements MessageContentType, MessageContentType.Image @Nullable @Override public String getImageUrl() { - - if (messageParameters != null && messageParameters.size() > 0) { for (HashMap.Entry> entry : messageParameters.entrySet()) { Map individualHashMap = entry.getValue(); diff --git a/app/src/main/res/layout/item_custom_incoming_voice_message.xml b/app/src/main/res/layout/item_custom_incoming_voice_message.xml index 7c19ad934..0257b618a 100644 --- a/app/src/main/res/layout/item_custom_incoming_voice_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_voice_message.xml @@ -79,7 +79,7 @@ android:visibility="gone"/> - - - - Date: Tue, 29 Jun 2021 14:35:09 +0200 Subject: [PATCH 02/16] fix spinner color for outgoing voice messages Signed-off-by: Marcel Hibbe --- .../main/res/layout/item_custom_outcoming_voice_message.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/item_custom_outcoming_voice_message.xml b/app/src/main/res/layout/item_custom_outcoming_voice_message.xml index 3aff776a8..e029656bf 100644 --- a/app/src/main/res/layout/item_custom_outcoming_voice_message.xml +++ b/app/src/main/res/layout/item_custom_outcoming_voice_message.xml @@ -60,7 +60,8 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:progressTint="@color/fontAppbar" - android:visibility="gone"/> + android:visibility="gone" + android:indeterminateTint="@color/nc_outcoming_text_default"/> Date: Tue, 29 Jun 2021 17:24:57 +0200 Subject: [PATCH 03/16] fix voicemessage design for landscape mode Signed-off-by: Marcel Hibbe --- .../main/res/layout/item_custom_incoming_voice_message.xml | 4 ++-- .../main/res/layout/item_custom_outcoming_voice_message.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/item_custom_incoming_voice_message.xml b/app/src/main/res/layout/item_custom_incoming_voice_message.xml index 0257b618a..3665ed09b 100644 --- a/app/src/main/res/layout/item_custom_incoming_voice_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_voice_message.xml @@ -66,7 +66,7 @@ android:textSize="12sp" /> @@ -92,7 +92,7 @@ diff --git a/app/src/main/res/layout/item_custom_outcoming_voice_message.xml b/app/src/main/res/layout/item_custom_outcoming_voice_message.xml index e029656bf..4646b6a7e 100644 --- a/app/src/main/res/layout/item_custom_outcoming_voice_message.xml +++ b/app/src/main/res/layout/item_custom_outcoming_voice_message.xml @@ -49,7 +49,7 @@ android:visibility="gone" /> @@ -79,7 +79,7 @@ From c7bb6402fe7d994d31e7936a3b85550f3fefb047 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 29 Jun 2021 21:45:46 +0200 Subject: [PATCH 04/16] stop mediaPlayer in onDestroy a voice message now continues to play if app goes to background, but whenever the user returns he can pause or stop the playback (UI is updated). Also, the playback survives a screen orientation change. instead stopping the mediaPlayer in onDetach would stop playback when moving app to background but also stop the playback on a screen orientation change. Signed-off-by: Marcel Hibbe --- .../java/com/nextcloud/talk/controllers/ChatController.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index 0cb36d569..f4e8e8945 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -1436,8 +1436,6 @@ class ChatController(args: Bundle) : if (mentionAutocomplete != null && mentionAutocomplete!!.isPopupShowing) { mentionAutocomplete?.dismissPopup() } - - currentlyPlayedVoiceMessage?.let { stopMediaPlayer(it) } } override val title: String @@ -1459,6 +1457,8 @@ class ChatController(args: Bundle) : actionBar?.setIcon(null) } + currentlyPlayedVoiceMessage?.let { stopMediaPlayer(it) } + adapter = null inConversation = false } From 741748137a7e9e1f6ac836225f9274684dd48f74 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 29 Jun 2021 22:44:01 +0200 Subject: [PATCH 05/16] fix lint/spotbugs warnings Signed-off-by: Marcel Hibbe --- .../messages/IncomingVoiceMessageViewHolder.kt | 11 ++--------- .../messages/OutcomingVoiceMessageViewHolder.kt | 9 ++------- .../talk/adapters/messages/VoiceMessageInterface.kt | 4 ++-- .../nextcloud/talk/models/json/chat/ChatMessage.java | 11 ----------- .../res/layout/item_custom_incoming_voice_message.xml | 2 +- .../layout/item_custom_outcoming_voice_message.xml | 2 +- app/src/main/res/values/strings.xml | 3 +-- scripts/analysis/findbugs-results.txt | 2 +- 8 files changed, 10 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index ae4820d62..d43d6f79f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -91,7 +91,6 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders // parent message handling setParentMessageDataOnMessageItem(message) - updateDownloadState(message) binding.seekbar.max = message.voiceMessageDuration @@ -103,10 +102,8 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders binding.seekbar.progress = message.voiceMessagePlayedSeconds } else { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, R.drawable - .ic_baseline_play_arrow_voice_message_24 - ) + binding.playPauseBtn.icon = + ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) } if (message.isDownloadingVoiceMessage) { @@ -126,9 +123,6 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders message.resetVoiceMessage = false } - activity = itemView.context as Activity - - binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onStopTrackingTouch(seekBar: SeekBar) { // unused atm @@ -159,7 +153,6 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(workInfo.id) .observeForever { info: WorkInfo? -> if (info != null) { - when (info.state) { WorkInfo.State.RUNNING -> { Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder") diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index ef574968d..d2513e2de 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -102,10 +102,8 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders binding.seekbar.progress = message.voiceMessagePlayedSeconds } else { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, R.drawable - .ic_baseline_play_arrow_voice_message_24 - ) + binding.playPauseBtn.icon = + ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) } if (message.isDownloadingVoiceMessage) { @@ -125,9 +123,6 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders message.resetVoiceMessage = false } - activity = itemView.context as Activity - - binding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onStopTrackingTouch(seekBar: SeekBar) { // unused atm diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt index 4f4745cca..7d6f7c173 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt @@ -3,5 +3,5 @@ package com.nextcloud.talk.adapters.messages import com.nextcloud.talk.models.json.chat.ChatMessage interface VoiceMessageInterface { - fun updateMediaPlayerProgressBySlider(message : ChatMessage, progress : Int) -} \ No newline at end of file + fun updateMediaPlayerProgressBySlider(message: ChatMessage, progress: Int) +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java index 13023253c..41c5c48c3 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java @@ -90,22 +90,13 @@ public class ChatMessage implements MessageContentType, MessageContentType.Image @JsonField(name = "messageType") public String messageType; - public boolean isDownloadingVoiceMessage; public boolean resetVoiceMessage; public boolean isPlayingVoiceMessage; public int voiceMessageDuration; public int voiceMessagePlayedSeconds; - public VoiceMessageDownloadState voiceMessageDownloadState; public int voiceMessageDownloadProgress; - public enum VoiceMessageDownloadState { - NOT_STARTED, - RUNNING, - SUCCEEDED, - FAILED - } - @JsonIgnore List messageTypesToIgnore = Arrays.asList( MessageType.REGULAR_TEXT_MESSAGE, @@ -116,8 +107,6 @@ public class ChatMessage implements MessageContentType, MessageContentType.Image MessageType.SINGLE_NC_GEOLOCATION_MESSAGE, MessageType.VOICE_MESSAGE); - - public boolean hasFileAttachment() { if (messageParameters != null && messageParameters.size() > 0) { for (HashMap.Entry> entry : messageParameters.entrySet()) { diff --git a/app/src/main/res/layout/item_custom_incoming_voice_message.xml b/app/src/main/res/layout/item_custom_incoming_voice_message.xml index 3665ed09b..17dffdabe 100644 --- a/app/src/main/res/layout/item_custom_incoming_voice_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_voice_message.xml @@ -83,7 +83,7 @@ style="@style/Widget.AppTheme.Button.IconButton" android:layout_width="48dp" android:layout_height="48dp" - android:contentDescription="@string/play_voice_message" + android:contentDescription="@string/play_pause_voice_message" android:visibility="visible" app:cornerRadius="@dimen/button_corner_radius" app:icon="@drawable/ic_baseline_play_arrow_voice_message_24" diff --git a/app/src/main/res/layout/item_custom_outcoming_voice_message.xml b/app/src/main/res/layout/item_custom_outcoming_voice_message.xml index 4646b6a7e..bc412aa13 100644 --- a/app/src/main/res/layout/item_custom_outcoming_voice_message.xml +++ b/app/src/main/res/layout/item_custom_outcoming_voice_message.xml @@ -68,7 +68,7 @@ style="@style/Widget.AppTheme.Button.IconButton" android:layout_width="48dp" android:layout_height="48dp" - android:contentDescription="@string/play_voice_message" + android:contentDescription="@string/play_pause_voice_message" android:visibility="visible" app:rippleColor="#1FFFFFFF" app:cornerRadius="@dimen/button_corner_radius" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fcef576fb..afa9e5c2a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -389,8 +389,7 @@ Hold to record, release to send. Record voice message << Slide to cancel - Play voice message - Pause voice message + Play/pause voice message Permission for audio recording is required diff --git a/scripts/analysis/findbugs-results.txt b/scripts/analysis/findbugs-results.txt index ce163e7b6..2ae9f6c7c 100644 --- a/scripts/analysis/findbugs-results.txt +++ b/scripts/analysis/findbugs-results.txt @@ -1 +1 @@ -440 \ No newline at end of file +441 \ No newline at end of file From 6fc83bbca0b5862c509c38ff9a8fed79890dd568 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 29 Jun 2021 23:09:39 +0200 Subject: [PATCH 06/16] fix klint warnings Signed-off-by: Marcel Hibbe --- .../adapters/messages/IncomingVoiceMessageViewHolder.kt | 6 ++---- .../adapters/messages/OutcomingVoiceMessageViewHolder.kt | 6 ++---- .../java/com/nextcloud/talk/controllers/ChatController.kt | 6 ++++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index d43d6f79f..80fbeac03 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -115,10 +115,8 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders if (message.resetVoiceMessage) { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, R.drawable - .ic_baseline_play_arrow_voice_message_24 - ) + binding.playPauseBtn.icon = + ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) binding.seekbar.progress = SEEKBAR_START message.resetVoiceMessage = false } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index d2513e2de..f0223cf34 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -115,10 +115,8 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders if (message.resetVoiceMessage) { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = ContextCompat.getDrawable( - context!!, R.drawable - .ic_baseline_play_arrow_voice_message_24 - ) + binding.playPauseBtn.icon = + ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) binding.seekbar.progress = SEEKBAR_START message.resetVoiceMessage = false } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index f4e8e8945..50ce9674b 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -191,7 +191,8 @@ class ChatController(args: Bundle) : MessagesListAdapter.OnLoadMoreListener, MessagesListAdapter.Formatter, MessagesListAdapter.OnMessageViewLongClickListener, - ContentChecker, VoiceMessageInterface { + ContentChecker, + VoiceMessageInterface { private val binding: ControllerChatBinding by viewBinding(ControllerChatBinding::bind) @@ -498,7 +499,8 @@ class ChatController(args: Bundle) : .setAutoPlayAnimations(true) .build() imageView.controller = draweeController - }, this + }, + this ) } else { binding.messagesListView.visibility = View.VISIBLE From f435646b23d1a0c4cc17a77919ea55753991d967 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 10:11:35 +0200 Subject: [PATCH 07/16] Add license header --- .../messages/VoiceMessageInterface.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt index 7d6f7c173..d61ae48a9 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt @@ -1,3 +1,23 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2021 Marcel Hibbe + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.nextcloud.talk.adapters.messages import com.nextcloud.talk.models.json.chat.ChatMessage @@ -5,3 +25,4 @@ import com.nextcloud.talk.models.json.chat.ChatMessage interface VoiceMessageInterface { fun updateMediaPlayerProgressBySlider(message: ChatMessage, progress: Int) } + From 5b457a67cb8315e389a34fb5321e6bac73c7371d Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 10:11:53 +0200 Subject: [PATCH 08/16] remove unused member variable Signed-off-by: Andy Scherzinger --- .../talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index f0223cf34..4a8efbeaa 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -57,7 +57,6 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders private val binding: ItemCustomOutcomingVoiceMessageBinding = ItemCustomOutcomingVoiceMessageBinding.bind(itemView) - private val realView: View = itemView @JvmField @Inject From a393685a632c2c3cd1aa16dfb704c18693196b11 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 10:15:11 +0200 Subject: [PATCH 09/16] else/if rather than if/if Signed-off-by: Andy Scherzinger --- .../talk/adapters/messages/TalkMessagesListAdapter.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java index 859276eee..916253a5c 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java @@ -51,11 +51,8 @@ public class TalkMessagesListAdapter extends MessagesListAda if (holder instanceof IncomingVoiceMessageViewHolder) { ((IncomingVoiceMessageViewHolder) holder).assignAdapter(chatController); - } - - if (holder instanceof OutcomingVoiceMessageViewHolder) { + } else if (holder instanceof OutcomingVoiceMessageViewHolder) { ((OutcomingVoiceMessageViewHolder) holder).assignAdapter(chatController); } - } } From 7bca54373f1f714fbae03eb8f084dc583376629d Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 10:38:52 +0200 Subject: [PATCH 10/16] Improve ktlint Signed-off-by: Andy Scherzinger --- .../messages/IncomingVoiceMessageViewHolder.kt | 18 ++++++++++++------ .../OutcomingVoiceMessageViewHolder.kt | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 80fbeac03..5ded5d0d1 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -97,13 +97,17 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders if (message.isPlayingVoiceMessage) { binding.progressBar.visibility = View.GONE binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = - ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_pause_voice_message_24) + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, + R.drawable.ic_baseline_pause_voice_message_24 + ) binding.seekbar.progress = message.voiceMessagePlayedSeconds } else { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = - ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, + R.drawable.ic_baseline_play_arrow_voice_message_24 + ) } if (message.isDownloadingVoiceMessage) { @@ -115,8 +119,10 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders if (message.resetVoiceMessage) { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = - ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, + R.drawable.ic_baseline_play_arrow_voice_message_24 + ) binding.seekbar.progress = SEEKBAR_START message.resetVoiceMessage = false } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index 4a8efbeaa..f6f1077b0 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -96,13 +96,17 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders if (message.isPlayingVoiceMessage) { binding.progressBar.visibility = View.GONE binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = - ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_pause_voice_message_24) + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, + R.drawable.ic_baseline_pause_voice_message_24 + ) binding.seekbar.progress = message.voiceMessagePlayedSeconds } else { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = - ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, + R.drawable.ic_baseline_play_arrow_voice_message_24 + ) } if (message.isDownloadingVoiceMessage) { @@ -114,8 +118,10 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders if (message.resetVoiceMessage) { binding.playPauseBtn.visibility = View.VISIBLE - binding.playPauseBtn.icon = - ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_play_arrow_voice_message_24) + binding.playPauseBtn.icon = ContextCompat.getDrawable( + context!!, + R.drawable.ic_baseline_play_arrow_voice_message_24 + ) binding.seekbar.progress = SEEKBAR_START message.resetVoiceMessage = false } From 78cc0df7bd37152e2a3532fd59e84c3914009537 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 10:49:30 +0200 Subject: [PATCH 11/16] spotbugs: use literal as comparison base Signed-off-by: Andy Scherzinger --- .../items/MentionAutocompleteItem.java | 63 ++++++++++++------- scripts/analysis/findbugs-results.txt | 2 +- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java index 714b17dd6..2d1fec291 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java @@ -45,17 +45,20 @@ import eu.davidea.flexibleadapter.utils.FlexibleUtils; public class MentionAutocompleteItem extends AbstractFlexibleItem implements IFilterable { + public static final String SOURCE_CALLS = "calls"; + public static final String SOURCE_GUESTS = "guests"; private String objectId; private String displayName; private String source; private UserEntity currentUser; private Context context; - public MentionAutocompleteItem(String objectId, - String displayName, - String source, - UserEntity currentUser, - Context activityContext) { + public MentionAutocompleteItem( + String objectId, + String displayName, + String source, + UserEntity currentUser, + Context activityContext) { this.objectId = objectId; this.displayName = displayName; this.source = source; @@ -102,19 +105,27 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem adapter, UserItem.UserItemViewHolder holder, int position, List payloads) { + public void bindViewHolder( + FlexibleAdapter adapter, + UserItem.UserItemViewHolder holder, + int position, + List payloads) { holder.contactDisplayName.setTextColor(ResourcesCompat.getColor(context.getResources(), - R.color.conversation_item_header, - null)); + R.color.conversation_item_header, + null)); if (adapter.hasFilter()) { - FlexibleUtils.highlightText(holder.contactDisplayName, displayName, - String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication() - .getResources().getColor(R.color.colorPrimary)); + FlexibleUtils.highlightText(holder.contactDisplayName, + displayName, + String.valueOf(adapter.getFilter(String.class)), + NextcloudTalkApplication.Companion.getSharedApplication() + .getResources().getColor(R.color.colorPrimary)); if (holder.contactMentionId != null) { - FlexibleUtils.highlightText(holder.contactMentionId, "@" + objectId, - String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication() - .getResources().getColor(R.color.colorPrimary)); + FlexibleUtils.highlightText(holder.contactMentionId, + "@" + objectId, + String.valueOf(adapter.getFilter(String.class)), + NextcloudTalkApplication.Companion.getSharedApplication() + .getResources().getColor(R.color.colorPrimary)); } } else { holder.contactDisplayName.setText(displayName); @@ -123,16 +134,19 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem Date: Wed, 30 Jun 2021 11:15:10 +0200 Subject: [PATCH 12/16] use stable release of popup bubble lib Signed-off-by: Andy Scherzinger --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 879b904ea..15f2dd8c2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -267,7 +267,7 @@ dependencies { implementation 'com.novoda:merlin:1.2.1' implementation 'com.github.Kennyc1012:BottomSheet:2.4.1' - implementation 'com.github.nextcloud:PopupBubble:master-SNAPSHOT' + implementation 'com.github.nextcloud:PopupBubble:1.0.6' implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation('eu.medsea.mimeutil:mime-util:2.1.3', { From 195bdfb05a2986425bae3079beb7ff5733dd98fb Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 12:17:27 +0200 Subject: [PATCH 13/16] extract visibility toggle for play/pause Vs. loading-animation Signed-off-by: Andy Scherzinger --- .../IncomingVoiceMessageViewHolder.kt | 28 +++++++++++-------- .../OutcomingVoiceMessageViewHolder.kt | 28 +++++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 5ded5d0d1..7554817d7 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -95,8 +95,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders binding.seekbar.max = message.voiceMessageDuration if (message.isPlayingVoiceMessage) { - binding.progressBar.visibility = View.GONE - binding.playPauseBtn.visibility = View.VISIBLE + showPlayButton() binding.playPauseBtn.icon = ContextCompat.getDrawable( context!!, R.drawable.ic_baseline_pause_voice_message_24 @@ -111,8 +110,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders } if (message.isDownloadingVoiceMessage) { - binding.playPauseBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE + showVoiceMessageLoading() } else { binding.progressBar.visibility = View.GONE } @@ -152,26 +150,22 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders try { for (workInfo in workers.get()) { if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { - binding.progressBar.visibility = View.VISIBLE - binding.playPauseBtn.visibility = View.GONE + showVoiceMessageLoading() WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(workInfo.id) .observeForever { info: WorkInfo? -> if (info != null) { when (info.state) { WorkInfo.State.RUNNING -> { Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder") - binding.playPauseBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE + showVoiceMessageLoading() } WorkInfo.State.SUCCEEDED -> { Log.d(TAG, "WorkInfo.State.SUCCEEDED in ViewHolder") - binding.playPauseBtn.visibility = View.VISIBLE - binding.progressBar.visibility = View.GONE + showPlayButton() } WorkInfo.State.FAILED -> { Log.d(TAG, "WorkInfo.State.FAILED in ViewHolder") - binding.playPauseBtn.visibility = View.VISIBLE - binding.progressBar.visibility = View.GONE + showPlayButton() } else -> { } @@ -187,6 +181,16 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders } } + private fun showPlayButton() { + binding.playPauseBtn.visibility = View.VISIBLE + binding.progressBar.visibility = View.GONE + } + + private fun showVoiceMessageLoading() { + binding.playPauseBtn.visibility = View.GONE + binding.progressBar.visibility = View.VISIBLE + } + private fun setAvatarAndAuthorOnMessageItem(message: ChatMessage) { val author: String = message.actorDisplayName if (!TextUtils.isEmpty(author)) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index f6f1077b0..0d652c666 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -94,8 +94,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders binding.seekbar.max = message.voiceMessageDuration if (message.isPlayingVoiceMessage) { - binding.progressBar.visibility = View.GONE - binding.playPauseBtn.visibility = View.VISIBLE + showPlayButton() binding.playPauseBtn.icon = ContextCompat.getDrawable( context!!, R.drawable.ic_baseline_pause_voice_message_24 @@ -110,8 +109,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders } if (message.isDownloadingVoiceMessage) { - binding.playPauseBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE + showVoiceMessageLoading() } else { binding.progressBar.visibility = View.GONE } @@ -172,8 +170,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders try { for (workInfo in workers.get()) { if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) { - binding.progressBar.visibility = View.VISIBLE - binding.playPauseBtn.visibility = View.GONE + showVoiceMessageLoading() WorkManager.getInstance(context!!).getWorkInfoByIdLiveData(workInfo.id) .observeForever { info: WorkInfo? -> if (info != null) { @@ -181,18 +178,15 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders when (info.state) { WorkInfo.State.RUNNING -> { Log.d(TAG, "WorkInfo.State.RUNNING in ViewHolder") - binding.playPauseBtn.visibility = View.GONE - binding.progressBar.visibility = View.VISIBLE + showVoiceMessageLoading() } WorkInfo.State.SUCCEEDED -> { Log.d(TAG, "WorkInfo.State.SUCCEEDED in ViewHolder") - binding.playPauseBtn.visibility = View.VISIBLE - binding.progressBar.visibility = View.GONE + showPlayButton() } WorkInfo.State.FAILED -> { Log.d(TAG, "WorkInfo.State.FAILED in ViewHolder") - binding.playPauseBtn.visibility = View.VISIBLE - binding.progressBar.visibility = View.GONE + showPlayButton() } else -> { } @@ -208,6 +202,16 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders } } + private fun showPlayButton() { + binding.playPauseBtn.visibility = View.VISIBLE + binding.progressBar.visibility = View.GONE + } + + private fun showVoiceMessageLoading() { + binding.playPauseBtn.visibility = View.GONE + binding.progressBar.visibility = View.VISIBLE + } + private fun setParentMessageDataOnMessageItem(message: ChatMessage) { if (!message.isDeleted && message.parentMessage != null) { val parentChatMessage = message.parentMessage From 3e570186154a55d3a73065fbef31490b469fb3fd Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 13:12:15 +0200 Subject: [PATCH 14/16] remove unused member variables Signed-off-by: Andy Scherzinger --- .../adapters/messages/IncomingVoiceMessageViewHolder.kt | 3 --- .../adapters/messages/OutcomingVoiceMessageViewHolder.kt | 6 ------ 2 files changed, 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 7554817d7..40d06ef08 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -25,7 +25,6 @@ package com.nextcloud.talk.adapters.messages import android.annotation.SuppressLint -import android.app.Activity import android.content.Context import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable @@ -71,8 +70,6 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders lateinit var message: ChatMessage - lateinit var activity: Activity - lateinit var voiceMessageInterface: VoiceMessageInterface @SuppressLint("SetTextI18n") diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index 0d652c666..335940f1e 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -23,10 +23,8 @@ package com.nextcloud.talk.adapters.messages import android.annotation.SuppressLint -import android.app.Activity import android.content.Context import android.graphics.PorterDuff -import android.media.MediaPlayer import android.os.Handler import android.util.Log import android.view.View @@ -68,10 +66,6 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders lateinit var message: ChatMessage - lateinit var activity: Activity - - var mediaPlayer: MediaPlayer? = null - lateinit var handler: Handler lateinit var voiceMessageInterface: VoiceMessageInterface From d37783d7a00e8a062cb6b0f92c40836035c4f3d6 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 13:38:48 +0200 Subject: [PATCH 15/16] fix ktlint Signed-off-by: Andy Scherzinger --- .../nextcloud/talk/adapters/messages/VoiceMessageInterface.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt index d61ae48a9..84ac39040 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/VoiceMessageInterface.kt @@ -25,4 +25,3 @@ import com.nextcloud.talk.models.json.chat.ChatMessage interface VoiceMessageInterface { fun updateMediaPlayerProgressBySlider(message: ChatMessage, progress: Int) } - From 60d14f3b3534f2b04ea9999a9b74f5654e30862e Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 30 Jun 2021 13:44:00 +0200 Subject: [PATCH 16/16] SuppressLint("SetTextI18n") Signed-off-by: Andy Scherzinger --- .../com/nextcloud/talk/adapters/items/ConversationItem.java | 2 ++ scripts/analysis/lint-results.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java index 4a146e3fc..91b2d0fcd 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java @@ -22,6 +22,7 @@ package com.nextcloud.talk.adapters.items; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; @@ -105,6 +106,7 @@ public class ConversationItem extends AbstractFlexibleItem adapter, ConversationItemViewHolder holder, int position, List payloads) { Context appContext = diff --git a/scripts/analysis/lint-results.txt b/scripts/analysis/lint-results.txt index 96f95f5ca..210a55682 100644 --- a/scripts/analysis/lint-results.txt +++ b/scripts/analysis/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 3 errors and 275 warnings + Lint Report: 3 errors and 274 warnings