diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java index 06e7084af..85d4626d8 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java @@ -57,6 +57,7 @@ public class IncomingPreviewMessageViewHolder extends PreviewMessageViewHolder { super.onBind(message); if(!message.isVoiceMessage() && !Objects.equals(message.getMessage(), "{file}") + && message.getEnableCaption() ) { Spanned processedMessageText = null; binding.incomingPreviewMessageBubble.setBackgroundResource(R.drawable.shape_grouped_incoming_message); diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java index 618d757b2..1ab4291c0 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java @@ -56,6 +56,7 @@ public class OutcomingPreviewMessageViewHolder extends PreviewMessageViewHolder super.onBind(message); if(!message.isVoiceMessage() && !Objects.equals(message.getMessage(), "{file}") + && message.getEnableCaption() ) { Spanned processedMessageText = null; binding.outgoingPreviewMessageBubble.setBackgroundResource(R.drawable.shape_grouped_outcoming_message); diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index 3ace986ef..eddb0b9b9 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -246,6 +246,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode +import org.json.JSONException +import org.json.JSONObject import retrofit2.HttpException import retrofit2.Response import java.io.File @@ -2673,16 +2675,25 @@ class ChatActivity : } private fun uploadFiles(files: MutableList, caption: String = "") { - for (i in 0 until files.size) { - if (i == files.size - 1) { - uploadFile(files[i], false, caption) - } else { - uploadFile(files[i], false) - } + val captionJsonObject = if (caption != "") { + JSONObject( + mapOf( + "caption" to mapOf( + "groupID" to SystemClock.elapsedRealtime(), + "captionText" to "\"$caption\"" + ).toString() + ) + ) + } else { + null + } + + for (file in files) { + uploadFile(file, false, captionJsonObject) } } - private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "") { + private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, metaDataJSONObject: JSONObject? = null) { var metaData = "" if (!participantPermissions.hasChatPermission()) { @@ -2694,8 +2705,9 @@ class ChatActivity : metaData = VOICE_MESSAGE_META_DATA } - if (caption != "") { - metaData = "{\"caption\":\"$caption\"}" + metaDataJSONObject?.let { + metaData = metaDataJSONObject.toString() + Log.d("Julius", "MetaData: $metaData") } try { @@ -3256,6 +3268,14 @@ class ChatActivity : processCallStartedMessages(chatMessageList) + val lastTen = adapter?.items?.take(ADAPTER_FILTER_LIMIT) + val prunedList = mutableListOf() + for (item in lastTen!!) { + if (item.item is ChatMessage) prunedList.add(item.item as ChatMessage) + } + prunedList.addAll(chatMessageList) + processFileCaptions(prunedList) + updateReadStatusOfAllMessages(newXChatLastCommonRead) adapter?.notifyDataSetChanged() @@ -3316,6 +3336,28 @@ class ChatActivity : } } + @SuppressLint("NotifyDataSetChanged", "NestedBlockDepth") + private fun processFileCaptions(chatMessageList: List) { + val captionMap = mutableMapOf() + for (message in chatMessageList.reversed()) { + if (message.hasFileAttachment()) { + try { + val obj = JSONObject(message.message!!) + val groupID = obj.getLong("groupID") + val caption = obj.getString("captionText") + message.message = caption + if (captionMap.contains(groupID)) { + captionMap[groupID]!!.enableCaption = false + } + captionMap[groupID] = message + captionMap[groupID]!!.enableCaption = true + } catch (e: JSONException) { + Log.w(TAG, "File caption not in JSON form: $e") + } + } + } + } + private fun setupFieldsForPullChatMessages( lookIntoFuture: Boolean, xChatLastCommonRead: Int?, @@ -4608,5 +4650,6 @@ class ChatActivity : private const val MILISEC_15: Long = 15 private const val LINEBREAK = "\n" private const val CURSOR_KEY = "_cursor" + private const val ADAPTER_FILTER_LIMIT = 3 } } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt index c9d70038a..187ccaf96 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt @@ -147,7 +147,9 @@ data class ChatMessage( var hiddenByCollapse: Boolean = false, - var openWhenDownloaded: Boolean = true + var openWhenDownloaded: Boolean = true, + + var enableCaption: Boolean = false ) : Parcelable, MessageContentType, MessageContentType.Image { diff --git a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt index 786d9f7f4..37a289345 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt @@ -38,6 +38,9 @@ import io.noties.markwon.core.MarkwonTheme import io.noties.markwon.ext.strikethrough.StrikethroughPlugin import io.noties.markwon.ext.tasklist.TaskListDrawable import io.noties.markwon.ext.tasklist.TaskListPlugin +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject class MessageUtils(val context: Context) { fun enrichChatReplyMessageText( @@ -171,7 +174,20 @@ class MessageUtils(val context: Context) { return markwon.toMarkdown(markdown) } + @Suppress("SwallowedException") companion object { + fun isJSONValid(test: String): Boolean { + try { + JSONObject(test) + } catch (ex: JSONException) { + try { + JSONArray(test) + } catch (ex1: JSONException) { + return false + } + } + return true + } private const val TAG = "MessageUtils" const val MAX_REPLY_LENGTH = 250 }