From 683f924556567ffbe3f9cd9c96829d14a87aa35d Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 9 Feb 2024 10:03:57 +0100 Subject: [PATCH 1/3] Add editor name and message timestamp to MessageActionsDialog Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 14 +-- .../OutcomingTextMessageViewHolder.kt | 15 ++-- .../com/nextcloud/talk/chat/ChatActivity.kt | 90 ++++++++++++++++++- .../talk/models/json/chat/ChatMessage.kt | 12 +++ .../talk/ui/dialog/MessageActionsDialog.kt | 24 ++++- .../res/layout/dialog_message_actions.xml | 35 ++++++++ app/src/main/res/values/strings.xml | 3 +- 7 files changed, 175 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt index ae9d35fcb..961ddeb88 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt @@ -113,16 +113,14 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.text = processedMessageText - if (message.parentMessage?.id != null && message.systemMessageType == ChatMessage.SystemMessageType - .MESSAGE_EDITED - ) { + if (message.lastEditTimestamp != 0L && !message.isDeleted) { binding.messageType.visibility = View.VISIBLE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp) } else { binding.messageType.visibility = View.GONE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) } - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) - // parent message handling if (!message.isDeleted && message.parentMessage != null) { processParentMessage(message) @@ -244,6 +242,12 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } } + fun updateMessage(message: ChatMessage) { + binding.messageText.text = message.message + binding.messageType.visibility = View.VISIBLE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp) + } + fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) { this.commonMessageInterface = commonMessageInterface } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt index 9142ee679..7d8f2947f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt @@ -100,18 +100,17 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH setBubbleOnChatMessage(message) binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - if (message.parentMessage?.id != null && message.systemMessageType == ChatMessage.SystemMessageType - .MESSAGE_EDITED - ) { - binding.messageType.visibility = View.VISIBLE - } else { - binding.messageType.visibility = View.GONE - } binding.messageTime.layoutParams = layoutParams viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT) binding.messageText.text = processedMessageText - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) + if (message.lastEditTimestamp != 0L && !message.isDeleted) { + binding.messageType.visibility = View.VISIBLE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp) + } else { + binding.messageType.visibility = View.GONE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) + } // parent message handling if (!message.isDeleted && message.parentMessage != null) { 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 aaa3c5c56..499821afa 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -922,6 +922,13 @@ class ChatActivity : message.message = messageEdited.ocs?.data?.parentMessage?.text adapter?.update(message) adapter?.notifyDataSetChanged() + + // val inflater = LayoutInflater.from(context) + // val outgoingTextViewLayout = inflater.inflate(R.layout.item_custom_incoming_text_message, null) + // val messageType = outgoingTextViewLayout.findViewById(R.id.messageType) + // val messageTime = outgoingTextViewLayout.findViewById(R.id.messageTime) + // messageType.visibility = View.VISIBLE + // messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp) clearEditUI() } @@ -2791,8 +2798,9 @@ class ChatActivity : } } - private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "") { + private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "", token: String = "") { var metaData = "" + var room = "" if (!participantPermissions.hasChatPermission()) { Log.w(TAG, "uploading file(s) is forbidden because of missing attendee permissions") @@ -2807,11 +2815,13 @@ class ChatActivity : metaData = "{\"caption\":\"$caption\"}" } + if (token == "") room = roomToken else room = token + try { require(fileUri.isNotEmpty()) UploadAndShareFilesWorker.upload( fileUri, - roomToken, + room, currentConversation?.displayName!!, metaData ) @@ -4287,6 +4297,82 @@ class ChatActivity : } } + fun shareToNotes(message: ChatMessage, roomToken: String) { + val apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1)) + val type = message.getCalculateMessageType() + var shareUri: Uri? = null + var data: HashMap? + var metaData: String = "" + var objectId: String = "" + if (message.hasFileAttachment()) { + val filename = message.selectedIndividualHashMap!!["name"] + path = applicationContext.cacheDir.absolutePath + "/" + filename + shareUri = FileProvider.getUriForFile( + this, + BuildConfig.APPLICATION_ID, + File(path) + ) + + this.grantUriPermission( + applicationContext.packageName, + shareUri, + Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION + ) + } else if (message.hasGeoLocation()) { + data = message.messageParameters?.get("object") + objectId = data?.get("id")!! + val name = data.get("name")!! + val lat = data.get("latitude")!! + val lon = data.get("longitude")!! + metaData = + "{\"type\":\"geo-location\",\"id\":\"geo:$lat,$lon\",\"latitude\":\"$lat\"," + + "\"longitude\":\"$lon\",\"name\":\"$name\"}" + } + + when (type) { + ChatMessage.MessageType.VOICE_MESSAGE -> { + uploadFile(shareUri.toString(), true, token = roomToken) + Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() + } + ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE -> { + val caption = if (message.message != "{file}") message.message else "" + if (null != shareUri) { + try { + context.contentResolver.openInputStream(shareUri)?.close() + uploadFile(shareUri.toString(), false, caption!!, roomToken) + Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() + } catch (e: java.lang.Exception) { + Log.w(TAG, "File corresponding to the uri does not exist " + shareUri.toString()) + downloadFileToCache(message, false) { + uploadFile(shareUri.toString(), false, caption!!, roomToken) + Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() + } + } + } + } + ChatMessage.MessageType.SINGLE_NC_GEOLOCATION_MESSAGE -> { + chatViewModel.shareLocationToNotes( + credentials!!, + ApiUtils.getUrlToSendLocation(apiVersion, conversationUser!!.baseUrl, roomToken), + "geo-location", + objectId, + metaData + ) + Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() + } + ChatMessage.MessageType.REGULAR_TEXT_MESSAGE -> { + chatViewModel.shareToNotes( + credentials!!, + ApiUtils.getUrlForChat(apiVersion, conversationUser!!.baseUrl, roomToken), + message.message!!, + conversationUser!!.displayName!! + ) + Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show() + } + else -> {} + } + } + fun openInFilesApp(message: ChatMessage) { val keyID = message.selectedIndividualHashMap!![PreviewMessageViewHolder.KEY_ID] val link = message.selectedIndividualHashMap!!["link"] 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 3b6db4fd7..467549314 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 @@ -121,6 +121,18 @@ data class ChatMessage( @JsonField(name = ["markdown"]) var renderMarkdown: Boolean? = null, + @JsonField(name = ["lastEditActorDisplayName"]) + var lastEditActorDisplayName: String? = null, + + @JsonField(name = ["lastEditActorId"]) + var lastEditActorId: String? = null, + + @JsonField(name = ["lastEditActorType"]) + var lastEditActorType: String? = null, + + @JsonField(name = ["lastEditTimestamp"]) + var lastEditTimestamp: Long = 0, + var isDownloadingVoiceMessage: Boolean = false, var resetVoiceMessage: Boolean = false, diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt index 5f9847047..4431551ff 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt @@ -51,6 +51,7 @@ import com.nextcloud.talk.repositories.reactions.ReactionsRepository import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ConversationUtils +import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew import com.vanniktech.emoji.EmojiPopup import com.vanniktech.emoji.EmojiTextView @@ -78,6 +79,9 @@ class MessageActionsDialog( @Inject lateinit var reactionsRepository: ReactionsRepository + @Inject + lateinit var dateUtils: DateUtils + private lateinit var dialogMessageActionsBinding: DialogMessageActionsBinding private lateinit var popup: EmojiPopup @@ -88,6 +92,11 @@ class MessageActionsDialog( private val messageHasRegularText = ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message .getCalculateMessageType() && !message.isDeleted + private val isMessageEditable = CapabilitiesUtilNew.hasSpreedFeatureCapability( + user, + "edit-messages" + ) && !message.isDeleted + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this) @@ -129,6 +138,7 @@ class MessageActionsDialog( ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() && CapabilitiesUtilNew.isTranslationsSupported(user) ) + initMenuEditorDetails(message.lastEditTimestamp != 0L && isMessageEditable) initMenuReplyToMessage(message.replyable && hasChatPermission) initMenuReplyPrivately( message.replyable && @@ -136,7 +146,7 @@ class MessageActionsDialog( hasUserActorId(message) && currentConversation?.type != ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL ) - initMenuEditMessage(CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "edit-messages")) + initMenuEditMessage(isMessageEditable) initMenuDeleteMessage(showMessageDeletionButton) initMenuForwardMessage( ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() && @@ -318,13 +328,13 @@ class MessageActionsDialog( dismiss() } } - dialogMessageActionsBinding.menuDeleteMessage.visibility = getVisibility(visible) } private fun initMenuEditMessage(visible: Boolean) { dialogMessageActionsBinding.menuEditMessage.setOnClickListener { chatActivity.editMessage(message) + Log.d("EDIT MESSAGE", "$message") dismiss() } @@ -353,6 +363,16 @@ class MessageActionsDialog( dialogMessageActionsBinding.menuReplyToMessage.visibility = getVisibility(visible) } + private fun initMenuEditorDetails(showEditorDetails: Boolean) { + if (showEditorDetails) { + val editedTime = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp) + val editorName = "Edited by " + message.lastEditActorDisplayName + dialogMessageActionsBinding.editorName.setText(editorName) + dialogMessageActionsBinding.editedTime.setText(editedTime) + } + dialogMessageActionsBinding.menuMessageEditedInfo.visibility = getVisibility(showEditorDetails) + } + private fun initMenuItemCopy(visible: Boolean) { if (visible) { dialogMessageActionsBinding.menuCopyMessage.setOnClickListener { diff --git a/app/src/main/res/layout/dialog_message_actions.xml b/app/src/main/res/layout/dialog_message_actions.xml index db7d0fe2c..575a64129 100644 --- a/app/src/main/res/layout/dialog_message_actions.xml +++ b/app/src/main/res/layout/dialog_message_actions.xml @@ -127,6 +127,41 @@ android:layout_height="wrap_content" android:orientation="vertical"> + + + + + + + + Retrieval failed Languages could not be retrieved Edit Message Icon - Edit message + Edit Send Edit Message Clear Edit Message Cannot Edit Messages older than 24 hours @@ -796,4 +796,5 @@ How to translate with transifex: (edited) Conversation not found Add to Notes + Edited by admin From 4e4cb26862c56fabde22e4a10ca054152d6fa171 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 9 Feb 2024 11:14:00 +0100 Subject: [PATCH 2/3] fix to update adapter for "edited messages" by system message This will update the message when an edit was made on other devices. So the system message will trigger that you are informed about a change. But instead to show the system message, you use it's information to immediately update the adapter. Signed-off-by: Marcel Hibbe --- .../java/com/nextcloud/talk/chat/ChatActivity.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 499821afa..bfac6f729 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -3857,6 +3857,10 @@ class ChatActivity : // delete poll system messages chatMessageIterator.remove() } else if (isEditMessage(currentMessage)) { + if (!chatMessageMap.containsKey(currentMessage.value.parentMessage!!.id)) { + setMessageAsEdited(currentMessage.value.parentMessage) + } + chatMessageIterator.remove() } } @@ -4464,6 +4468,17 @@ class ChatActivity : adapter?.update(messageTemp) } + private fun setMessageAsEdited(message: IMessage?) { + val messageTemp = message as ChatMessage + messageTemp.lastEditTimestamp = message.timestamp + + messageTemp.isOneToOneConversation = + currentConversation?.type == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL + messageTemp.activeUser = conversationUser + + adapter?.update(messageTemp) + } + private fun updateAdapterForReaction(message: IMessage?) { val messageTemp = message as ChatMessage From 6708aeebad2f1f201f7038d504f59ba2b361ba67 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 9 Feb 2024 11:16:21 +0100 Subject: [PATCH 3/3] fix to show message as edited after editing on own device Signed-off-by: Marcel Hibbe --- app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt | 1 + 1 file changed, 1 insertion(+) 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 bfac6f729..dfdd86104 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -920,6 +920,7 @@ class ChatActivity : } } message.message = messageEdited.ocs?.data?.parentMessage?.text + message.lastEditTimestamp = System.currentTimeMillis() adapter?.update(message) adapter?.notifyDataSetChanged()