From bfc9251e8026164a1f81c4ea41f38c1d0a8ed0e8 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Tue, 18 Feb 2025 17:55:52 +0100 Subject: [PATCH 01/15] align layout properly Signed-off-by: sowjanyakch --- .../layout/item_custom_incoming_text_message.xml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/item_custom_incoming_text_message.xml b/app/src/main/res/layout/item_custom_incoming_text_message.xml index 06f60829c..a6915b6a1 100644 --- a/app/src/main/res/layout/item_custom_incoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_text_message.xml @@ -64,11 +64,20 @@ app:layout_wrapBefore="true" tools:text="Talk to you later!" /> + + + Date: Wed, 19 Feb 2025 21:43:32 +0100 Subject: [PATCH 02/15] use interactive checkbox Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 75 ++++++++++++++++++- .../talk/utils/message/MessageUtils.kt | 2 +- .../item_custom_incoming_text_message.xml | 11 ++- 3 files changed, 83 insertions(+), 5 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 9fab9306c..c85d352a1 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 @@ -13,6 +13,10 @@ import android.content.Context import android.util.Log import android.util.TypedValue import android.view.View +import android.widget.CheckBox +import android.widget.LinearLayout +import androidx.core.text.toSpanned +import androidx.emoji2.widget.EmojiTextView import autodagger.AutoInjector import coil.load import com.nextcloud.talk.R @@ -20,12 +24,14 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.chat.data.model.ChatMessage +import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ChatMessageUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.TextMatchers +import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.preferences.AppPreferences import com.stfalcon.chatkit.messages.MessageHolders @@ -57,9 +63,16 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : @Inject lateinit var dateUtils: DateUtils + + @Inject + lateinit var currentUserProvider: CurrentUserProviderNew + lateinit var commonMessageInterface: CommonMessageInterface override fun onBind(message: ChatMessage) { + + val user = currentUserProvider.currentUser.blockingGet() + super.onBind(message) sharedApplication!!.componentApplication.inject(this) @@ -85,6 +98,9 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : itemView ) + val hasCheckboxes = processCheckboxes( binding.messageText, binding + .checkboxContainer, message, user) + val messageParameters = message.messageParameters if ( (messageParameters == null || messageParameters.size <= 0) && @@ -95,8 +111,10 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageAuthor.visibility = View.GONE } - binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - binding.messageText.text = processedMessageText + if (!hasCheckboxes) { + binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + binding.messageText.text = processedMessageText + } if (message.lastEditTimestamp != 0L && !message.isDeleted) { binding.messageEditIndicator.visibility = View.VISIBLE @@ -127,6 +145,55 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : ) } + + private fun processCheckboxes(messageTextView: EmojiTextView, checkBoxContainer: LinearLayout, + chatMessage: ChatMessage, user: User + ): Boolean { + + val message = chatMessage.message!!.toSpanned() + checkBoxContainer.removeAllViews() + val regex = """(- \[(X| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) + val matches = regex.findAll(message) + if (matches.none()) return false + val firstPart = message.toString().substringBefore("\n- [") + messageTextView.text = messageUtils.enrichChatMessageText( + binding.messageText.context, + firstPart, + true, + viewThemeUtils + ) + matches.forEach { matchResult -> + val isChecked = matchResult.groupValues[2] == "X" + val taskText = matchResult.groupValues[3].trim() + val checkBox = CheckBox(checkBoxContainer.context).apply { + text = taskText + this.isChecked = isChecked + setOnCheckedChangeListener { _, isChecked -> + //edit message + } + } + checkBoxContainer.addView(checkBox) + } + + checkBoxContainer.visibility = View.VISIBLE + + return true + } + + + private fun updateMessageWithCheckboxState(originalMessage: String, taskText: String, isChecked: Boolean): String { + val lines = originalMessage.split("\n") + val updatedLines = lines.map { line -> + if (line.contains(taskText)) { + val checkboxState = if (isChecked) "X" else " " + "- [$checkboxState] $taskText" + } else { + line + } + } + return updatedLines.joinToString("\n") + } + private fun longClickOnReaction(chatMessage: ChatMessage) { commonMessageInterface.onLongClickReactions(chatMessage) } @@ -235,4 +302,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : const val TEXT_SIZE_MULTIPLIER = 2.5 private val TAG = IncomingTextMessageViewHolder::class.java.simpleName } -} + + } + 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 3e4d43696..ffedb19d9 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 @@ -65,7 +65,7 @@ class MessageUtils(val context: Context) { } } - private fun enrichChatMessageText( + fun enrichChatMessageText( context: Context, message: String, incoming: Boolean, diff --git a/app/src/main/res/layout/item_custom_incoming_text_message.xml b/app/src/main/res/layout/item_custom_incoming_text_message.xml index a6915b6a1..0c9498de9 100644 --- a/app/src/main/res/layout/item_custom_incoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_text_message.xml @@ -64,6 +64,16 @@ app:layout_wrapBefore="true" tools:text="Talk to you later!" /> + + + + + Date: Thu, 20 Feb 2025 15:35:29 +0100 Subject: [PATCH 03/15] edit message on clicking checkboxes Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 89 +++++++++++++------ 1 file changed, 63 insertions(+), 26 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 c85d352a1..a5dc38afc 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 @@ -19,10 +19,12 @@ import androidx.core.text.toSpanned import androidx.emoji2.widget.EmojiTextView import autodagger.AutoInjector import coil.load +import com.google.android.material.snackbar.Snackbar import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.chat.ChatActivity +import com.nextcloud.talk.chat.data.ChatMessageRepository import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding @@ -63,16 +65,15 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : @Inject lateinit var dateUtils: DateUtils - @Inject lateinit var currentUserProvider: CurrentUserProviderNew lateinit var commonMessageInterface: CommonMessageInterface - override fun onBind(message: ChatMessage) { + @Inject + lateinit var chatRepository: ChatMessageRepository - val user = currentUserProvider.currentUser.blockingGet() - + override fun onBind(message: ChatMessage) { super.onBind(message) sharedApplication!!.componentApplication.inject(this) @@ -80,6 +81,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : colorizeMessageBubble(message) itemView.isSelected = false + val user = currentUserProvider.currentUser.blockingGet() var textSize = context.resources!!.getDimension(R.dimen.chat_text_size) @@ -98,8 +100,13 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : itemView ) - val hasCheckboxes = processCheckboxes( binding.messageText, binding - .checkboxContainer, message, user) + val hasCheckboxes = processCheckboxes( + binding.messageText, + binding + .checkboxContainer, + message, + user + ) val messageParameters = message.messageParameters if ( @@ -145,11 +152,12 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : ) } - - private fun processCheckboxes(messageTextView: EmojiTextView, checkBoxContainer: LinearLayout, - chatMessage: ChatMessage, user: User + private fun processCheckboxes( + messageTextView: EmojiTextView, + checkBoxContainer: LinearLayout, + chatMessage: ChatMessage, + user: User ): Boolean { - val message = chatMessage.message!!.toSpanned() checkBoxContainer.removeAllViews() val regex = """(- \[(X| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) @@ -165,33 +173,64 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : matches.forEach { matchResult -> val isChecked = matchResult.groupValues[2] == "X" val taskText = matchResult.groupValues[3].trim() + lateinit var updatedMessage: String val checkBox = CheckBox(checkBoxContainer.context).apply { text = taskText this.isChecked = isChecked setOnCheckedChangeListener { _, isChecked -> - //edit message + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + val apiVersion: Int = ApiUtils.getChatApiVersion( + user.capabilities?.spreedCapability!!, + intArrayOf(1) + ) + updatedMessage = + updateMessageWithCheckboxState(chatMessage.message!!, taskText, isChecked) + + chatRepository.editChatMessage( + user.getCredentials(), + ApiUtils.getUrlForChatMessage( + apiVersion, + user.baseUrl!!, + chatMessage.token!!, + chatMessage.id + ), + updatedMessage + ).collect { result -> + if (result.isSuccess) { + val editedMessage = result.getOrNull()?.ocs?.data?.parentMessage?.message ?: return@collect + chatMessage.message = editedMessage + } else { + Snackbar.make( + binding.root, + R.string.nc_common_error_sorry, + Snackbar.LENGTH_LONG + ).show() + } + } + } + if (chatMessage.lastEditTimestamp != 0L && !chatMessage.isDeleted) { + binding.messageEditIndicator.visibility = View.VISIBLE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp( + chatMessage + .lastEditTimestamp!! + ) + } + } } } checkBoxContainer.addView(checkBox) } - checkBoxContainer.visibility = View.VISIBLE - return true } - private fun updateMessageWithCheckboxState(originalMessage: String, taskText: String, isChecked: Boolean): String { - val lines = originalMessage.split("\n") - val updatedLines = lines.map { line -> - if (line.contains(taskText)) { - val checkboxState = if (isChecked) "X" else " " - "- [$checkboxState] $taskText" - } else { - line - } + val regex = """(- \[(X| )])\s*$taskText""".toRegex(RegexOption.MULTILINE) + return regex.replace(originalMessage) { + val checkboxState = if (isChecked) "X" else " " + "- [$checkboxState] $taskText" } - return updatedLines.joinToString("\n") } private fun longClickOnReaction(chatMessage: ChatMessage) { @@ -302,6 +341,4 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : const val TEXT_SIZE_MULTIPLIER = 2.5 private val TAG = IncomingTextMessageViewHolder::class.java.simpleName } - - } - +} From 0e118dbfd15e863e47ae075a6dc31570d72d97a0 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 20 Feb 2025 22:09:46 +0100 Subject: [PATCH 04/15] refactor code Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 135 ++++++++---------- .../item_custom_incoming_text_message.xml | 3 +- 2 files changed, 64 insertions(+), 74 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 a5dc38afc..fac458ecc 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 @@ -9,14 +9,13 @@ */ package com.nextcloud.talk.adapters.messages +import android.annotation.SuppressLint import android.content.Context import android.util.Log import android.util.TypedValue import android.view.View import android.widget.CheckBox -import android.widget.LinearLayout import androidx.core.text.toSpanned -import androidx.emoji2.widget.EmojiTextView import autodagger.AutoInjector import coil.load import com.google.android.material.snackbar.Snackbar @@ -85,82 +84,81 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : var textSize = context.resources!!.getDimension(R.dimen.chat_text_size) - var processedMessageText = messageUtils.enrichChatMessageText( - binding.messageText.context, - message, - true, - viewThemeUtils - ) - - processedMessageText = messageUtils.processMessageParameters( - binding.messageText.context, - viewThemeUtils, - processedMessageText!!, - message, - itemView - ) - val hasCheckboxes = processCheckboxes( - binding.messageText, - binding - .checkboxContainer, message, user ) - val messageParameters = message.messageParameters - if ( - (messageParameters == null || messageParameters.size <= 0) && - TextMatchers.isMessageWithSingleEmoticonOnly(message.text) - ) { - textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat() - itemView.isSelected = true - binding.messageAuthor.visibility = View.GONE + if(!hasCheckboxes){ + var processedMessageText = messageUtils.enrichChatMessageText( + binding.messageText.context, + message, + true, + viewThemeUtils + ) + + processedMessageText = messageUtils.processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) + + val messageParameters = message.messageParameters + if ( + (messageParameters == null || messageParameters.size <= 0) && + TextMatchers.isMessageWithSingleEmoticonOnly(message.text) + ) { + textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat() + itemView.isSelected = true + binding.messageAuthor.visibility = View.GONE + } + + binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + binding.messageText.text = processedMessageText + + if (message.lastEditTimestamp != 0L && !message.isDeleted) { + binding.messageEditIndicator.visibility = View.VISIBLE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp!!) + } else { + binding.messageEditIndicator.visibility = View.GONE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) + } + + // parent message handling + if (!message.isDeleted && message.parentMessageId != null) { + processParentMessage(message) + binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE + } else { + binding.messageQuote.quotedChatMessageView.visibility = View.GONE + } + + itemView.setTag(R.string.replyable_message_view_tag, message.replyable) + + Reaction().showReactions( + message, + ::clickOnReaction, + ::longClickOnReaction, + binding.reactions, + binding.messageText.context, + false, + viewThemeUtils + ) } - - if (!hasCheckboxes) { - binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - binding.messageText.text = processedMessageText - } - - if (message.lastEditTimestamp != 0L && !message.isDeleted) { - binding.messageEditIndicator.visibility = View.VISIBLE - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp!!) - } else { - binding.messageEditIndicator.visibility = View.GONE - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) - } - - // parent message handling - if (!message.isDeleted && message.parentMessageId != null) { - processParentMessage(message) - binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE - } else { - binding.messageQuote.quotedChatMessageView.visibility = View.GONE - } - - itemView.setTag(R.string.replyable_message_view_tag, message.replyable) - - Reaction().showReactions( - message, - ::clickOnReaction, - ::longClickOnReaction, - binding.reactions, - binding.messageText.context, - false, - viewThemeUtils - ) } + @SuppressLint("StringFormatMatches") private fun processCheckboxes( - messageTextView: EmojiTextView, - checkBoxContainer: LinearLayout, chatMessage: ChatMessage, user: User ): Boolean { val message = chatMessage.message!!.toSpanned() + val messageTextView = binding.messageText + val checkBoxContainer = binding.checkboxContainer + checkBoxContainer.removeAllViews() - val regex = """(- \[(X| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) + val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) val matches = regex.findAll(message) if (matches.none()) return false val firstPart = message.toString().substringBefore("\n- [") @@ -171,7 +169,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : viewThemeUtils ) matches.forEach { matchResult -> - val isChecked = matchResult.groupValues[2] == "X" + val isChecked = matchResult.groupValues[2] == "X" || matchResult.groupValues[2] == "x" val taskText = matchResult.groupValues[3].trim() lateinit var updatedMessage: String val checkBox = CheckBox(checkBoxContainer.context).apply { @@ -209,13 +207,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } } } - if (chatMessage.lastEditTimestamp != 0L && !chatMessage.isDeleted) { - binding.messageEditIndicator.visibility = View.VISIBLE - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp( - chatMessage - .lastEditTimestamp!! - ) - } } } } diff --git a/app/src/main/res/layout/item_custom_incoming_text_message.xml b/app/src/main/res/layout/item_custom_incoming_text_message.xml index 0c9498de9..6291dd8ec 100644 --- a/app/src/main/res/layout/item_custom_incoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_text_message.xml @@ -93,8 +93,8 @@ android:textColor="@color/no_emphasis_text" android:textIsSelectable="false" android:gravity = "end" - app:layout_alignSelf="flex_end" app:layout_flexGrow="1" + app:layout_alignSelf="flex_end" app:layout_wrapBefore="false" tools:text="12:38" /> @@ -110,7 +110,6 @@ app:layout_alignSelf="flex_end" android:text = "@string/hint_edited_message" android:textSize="12sp"> - From b7835fd462b43c9c1f8faae4ab73869798b82024 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 21 Feb 2025 10:06:59 +0100 Subject: [PATCH 05/15] handle multiple checkboxes Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 110 +++++++++--------- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 59 insertions(+), 53 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 fac458ecc..a9e772843 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 @@ -9,7 +9,6 @@ */ package com.nextcloud.talk.adapters.messages -import android.annotation.SuppressLint import android.content.Context import android.util.Log import android.util.TypedValue @@ -89,7 +88,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : user ) - if(!hasCheckboxes){ + if (!hasCheckboxes) { var processedMessageText = messageUtils.enrichChatMessageText( binding.messageText.context, message, @@ -115,8 +114,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageAuthor.visibility = View.GONE } - binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - binding.messageText.text = processedMessageText + binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + binding.messageText.text = processedMessageText if (message.lastEditTimestamp != 0L && !message.isDeleted) { binding.messageEditIndicator.visibility = View.VISIBLE @@ -148,11 +147,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } } - @SuppressLint("StringFormatMatches") - private fun processCheckboxes( - chatMessage: ChatMessage, - user: User - ): Boolean { + private fun processCheckboxes(chatMessage: ChatMessage, user: User): Boolean { val message = chatMessage.message!!.toSpanned() val messageTextView = binding.messageText val checkBoxContainer = binding.checkboxContainer @@ -160,70 +155,81 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : checkBoxContainer.removeAllViews() val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) val matches = regex.findAll(message) + if (matches.none()) return false + val firstPart = message.toString().substringBefore("\n- [") messageTextView.text = messageUtils.enrichChatMessageText( - binding.messageText.context, - firstPart, - true, - viewThemeUtils + binding.messageText.context, firstPart, true, viewThemeUtils ) + + val checkboxList = mutableListOf() + matches.forEach { matchResult -> val isChecked = matchResult.groupValues[2] == "X" || matchResult.groupValues[2] == "x" val taskText = matchResult.groupValues[3].trim() - lateinit var updatedMessage: String + val checkBox = CheckBox(checkBoxContainer.context).apply { text = taskText this.isChecked = isChecked - setOnCheckedChangeListener { _, isChecked -> - CoroutineScope(Dispatchers.Main).launch { - withContext(Dispatchers.IO) { - val apiVersion: Int = ApiUtils.getChatApiVersion( - user.capabilities?.spreedCapability!!, - intArrayOf(1) - ) - updatedMessage = - updateMessageWithCheckboxState(chatMessage.message!!, taskText, isChecked) - - chatRepository.editChatMessage( - user.getCredentials(), - ApiUtils.getUrlForChatMessage( - apiVersion, - user.baseUrl!!, - chatMessage.token!!, - chatMessage.id - ), - updatedMessage - ).collect { result -> - if (result.isSuccess) { - val editedMessage = result.getOrNull()?.ocs?.data?.parentMessage?.message ?: return@collect - chatMessage.message = editedMessage - } else { - Snackbar.make( - binding.root, - R.string.nc_common_error_sorry, - Snackbar.LENGTH_LONG - ).show() - } - } - } - } + setOnCheckedChangeListener { _, _ -> + updateCheckboxStates(chatMessage, user, checkboxList) } } checkBoxContainer.addView(checkBox) + checkboxList.add(checkBox) } + checkBoxContainer.visibility = View.VISIBLE return true } - private fun updateMessageWithCheckboxState(originalMessage: String, taskText: String, isChecked: Boolean): String { - val regex = """(- \[(X| )])\s*$taskText""".toRegex(RegexOption.MULTILINE) - return regex.replace(originalMessage) { - val checkboxState = if (isChecked) "X" else " " - "- [$checkboxState] $taskText" + private fun updateCheckboxStates(chatMessage: ChatMessage, user: User, checkboxes: List) { + CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + val apiVersion: Int = ApiUtils.getChatApiVersion( + user.capabilities?.spreedCapability!!, + intArrayOf(1) + ) + + val updatedMessage = updateMessageWithCheckboxStates(chatMessage.message!!, checkboxes) + + chatRepository.editChatMessage( + user.getCredentials(), + ApiUtils.getUrlForChatMessage(apiVersion, user.baseUrl!!, chatMessage.token!!, chatMessage.id), + updatedMessage + ).collect { result -> + withContext(Dispatchers.Main) { + if (result.isSuccess) { + val editedMessage = result.getOrNull()?.ocs?.data!!.parentMessage!! + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(editedMessage.lastEditTimestamp!!) + binding.messageEditIndicator.apply { + visibility = View.VISIBLE + text = String.format(context.getString(R.string.edited_by), editedMessage.lastEditActorType) + } + } else { + Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() + } + } + } + } } } + private fun updateMessageWithCheckboxStates(originalMessage: String, checkboxes: List): String { + var updatedMessage = originalMessage + val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) + + checkboxes.forEach { checkBox -> + updatedMessage = regex.replace(updatedMessage) { matchResult -> + val taskText = matchResult.groupValues[3].trim() + val checkboxState = if (checkboxes.find { it.text == taskText }?.isChecked == true) "X" else " " + "- [$checkboxState] $taskText" + } + } + return updatedMessage + } + private fun longClickOnReaction(chatMessage: ChatMessage) { commonMessageInterface.onLongClickReactions(chatMessage) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 47ca02e69..b830cc902 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -588,7 +588,7 @@ How to translate with transifex: Chat via %s Account not found Edit - + (edited by %1$s) Save Save to storage? From b323915d0fa09692b9f98c6418281b1de9957f21 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 21 Feb 2025 10:56:27 +0100 Subject: [PATCH 06/15] apply theming Signed-off-by: sowjanyakch --- .../adapters/messages/IncomingTextMessageViewHolder.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 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 a9e772843..069430e33 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 @@ -37,6 +37,7 @@ import com.nextcloud.talk.utils.preferences.AppPreferences import com.stfalcon.chatkit.messages.MessageHolders import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -71,6 +72,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : @Inject lateinit var chatRepository: ChatMessageRepository + private var job: Job? = null + override fun onBind(message: ChatMessage) { super.onBind(message) sharedApplication!!.componentApplication.inject(this) @@ -87,7 +90,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : message, user ) - if (!hasCheckboxes) { var processedMessageText = messageUtils.enrichChatMessageText( binding.messageText.context, @@ -178,6 +180,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } checkBoxContainer.addView(checkBox) checkboxList.add(checkBox) + viewThemeUtils.platform.themeCheckbox(checkBox) } checkBoxContainer.visibility = View.VISIBLE @@ -185,7 +188,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } private fun updateCheckboxStates(chatMessage: ChatMessage, user: User, checkboxes: List) { - CoroutineScope(Dispatchers.Main).launch { + job = CoroutineScope(Dispatchers.Main).launch { withContext(Dispatchers.IO) { val apiVersion: Int = ApiUtils.getChatApiVersion( user.capabilities?.spreedCapability!!, @@ -202,10 +205,9 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : withContext(Dispatchers.Main) { if (result.isSuccess) { val editedMessage = result.getOrNull()?.ocs?.data!!.parentMessage!! - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(editedMessage.lastEditTimestamp!!) + Log.d(TAG," EditedMessage: $editedMessage") binding.messageEditIndicator.apply { visibility = View.VISIBLE - text = String.format(context.getString(R.string.edited_by), editedMessage.lastEditActorType) } } else { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() From 47551284f6a75dfedd2a56ace41b73bc2c568909 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 21 Feb 2025 13:56:09 +0100 Subject: [PATCH 07/15] adjust layout Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 6 ++++-- .../layout/item_custom_incoming_text_message.xml | 16 ++++------------ 2 files changed, 8 insertions(+), 14 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 069430e33..0697fccb3 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 @@ -188,7 +188,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } private fun updateCheckboxStates(chatMessage: ChatMessage, user: User, checkboxes: List) { - job = CoroutineScope(Dispatchers.Main).launch { + job = CoroutineScope(Dispatchers.Main).launch { withContext(Dispatchers.IO) { val apiVersion: Int = ApiUtils.getChatApiVersion( user.capabilities?.spreedCapability!!, @@ -205,10 +205,12 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : withContext(Dispatchers.Main) { if (result.isSuccess) { val editedMessage = result.getOrNull()?.ocs?.data!!.parentMessage!! - Log.d(TAG," EditedMessage: $editedMessage") + Log.d(TAG, "EditedMessage: $editedMessage") binding.messageEditIndicator.apply { visibility = View.VISIBLE } + binding.messageTime.text = + dateUtils.getLocalTimeStringFromTimestamp(editedMessage.lastEditTimestamp!!) } else { Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() } diff --git a/app/src/main/res/layout/item_custom_incoming_text_message.xml b/app/src/main/res/layout/item_custom_incoming_text_message.xml index 6291dd8ec..884c3087d 100644 --- a/app/src/main/res/layout/item_custom_incoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_text_message.xml @@ -74,25 +74,17 @@ - - - Date: Fri, 21 Feb 2025 14:18:06 +0100 Subject: [PATCH 08/15] use constants Signed-off-by: sowjanyakch --- .../adapters/messages/IncomingTextMessageViewHolder.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 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 0697fccb3..2e3d62935 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 @@ -168,8 +168,9 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : val checkboxList = mutableListOf() matches.forEach { matchResult -> - val isChecked = matchResult.groupValues[2] == "X" || matchResult.groupValues[2] == "x" - val taskText = matchResult.groupValues[3].trim() + val isChecked = matchResult.groupValues[CHECKED_GROUP_INDEX] == "X" || + matchResult.groupValues[CHECKED_GROUP_INDEX] == "x" + val taskText = matchResult.groupValues[TASK_TEXT_GROUP_INDEX].trim() val checkBox = CheckBox(checkBoxContainer.context).apply { text = taskText @@ -341,5 +342,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : companion object { const val TEXT_SIZE_MULTIPLIER = 2.5 private val TAG = IncomingTextMessageViewHolder::class.java.simpleName + private const val CHECKED_GROUP_INDEX = 2 + private const val TASK_TEXT_GROUP_INDEX = 3 } } From 4abb28e4451d079034030054dd38a92f6616aad0 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 21 Feb 2025 14:56:58 +0100 Subject: [PATCH 09/15] fix detekt Signed-off-by: sowjanyakch --- .../adapters/messages/IncomingTextMessageViewHolder.kt | 9 ++++++--- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 7 insertions(+), 4 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 2e3d62935..1ce44b40a 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 @@ -84,12 +84,15 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : itemView.isSelected = false val user = currentUserProvider.currentUser.blockingGet() - var textSize = context.resources!!.getDimension(R.dimen.chat_text_size) - val hasCheckboxes = processCheckboxes( message, user ) + processMessage(message, hasCheckboxes) + } + + private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) { + var textSize = context.resources!!.getDimension(R.dimen.chat_text_size) if (!hasCheckboxes) { var processedMessageText = messageUtils.enrichChatMessageText( binding.messageText.context, @@ -227,7 +230,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : checkboxes.forEach { checkBox -> updatedMessage = regex.replace(updatedMessage) { matchResult -> - val taskText = matchResult.groupValues[3].trim() + val taskText = matchResult.groupValues[TASK_TEXT_GROUP_INDEX].trim() val checkboxState = if (checkboxes.find { it.text == taskText }?.isChecked == true) "X" else " " "- [$checkboxState] $taskText" } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b830cc902..47ca02e69 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -588,7 +588,7 @@ How to translate with transifex: Chat via %s Account not found Edit - (edited by %1$s) + Save Save to storage? From 8b44882e787d5f189628ea979c62e24b8a6d9a75 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 13 Mar 2025 15:43:50 +0100 Subject: [PATCH 10/15] edit checkbox messages directly Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 68 ++++---- .../OutcomingTextMessageViewHolder.kt | 153 ++++++++++++++++-- .../item_custom_outcoming_text_message.xml | 11 ++ 3 files changed, 184 insertions(+), 48 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 1ce44b40a..c1a22a94e 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 @@ -41,6 +41,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.util.Date import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -77,13 +78,10 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : override fun onBind(message: ChatMessage) { super.onBind(message) sharedApplication!!.componentApplication.inject(this) - setAvatarAndAuthorOnMessageItem(message) colorizeMessageBubble(message) - itemView.isSelected = false val user = currentUserProvider.currentUser.blockingGet() - val hasCheckboxes = processCheckboxes( message, user @@ -122,40 +120,46 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.text = processedMessageText - if (message.lastEditTimestamp != 0L && !message.isDeleted) { - binding.messageEditIndicator.visibility = View.VISIBLE - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp!!) - } else { - binding.messageEditIndicator.visibility = View.GONE - binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) - } - - // parent message handling - if (!message.isDeleted && message.parentMessageId != null) { - processParentMessage(message) - binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE - } else { - binding.messageQuote.quotedChatMessageView.visibility = View.GONE - } - - itemView.setTag(R.string.replyable_message_view_tag, message.replyable) - - Reaction().showReactions( - message, - ::clickOnReaction, - ::longClickOnReaction, - binding.reactions, - binding.messageText.context, - false, - viewThemeUtils - ) + }else{ + binding.messageText.text = "" } + + if (message.lastEditTimestamp != 0L && !message.isDeleted) { + binding.messageEditIndicator.visibility = View.VISIBLE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp!!) + } else { + binding.messageEditIndicator.visibility = View.GONE + binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) + } + // parent message handling + if (!message.isDeleted && message.parentMessageId != null) { + processParentMessage(message) + binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE + } else { + binding.messageQuote.quotedChatMessageView.visibility = View.GONE + } + + itemView.setTag(R.string.replyable_message_view_tag, message.replyable) + + Reaction().showReactions( + message, + ::clickOnReaction, + ::longClickOnReaction, + binding.reactions, + binding.messageText.context, + false, + viewThemeUtils + ) } private fun processCheckboxes(chatMessage: ChatMessage, user: User): Boolean { + val chatActivity = commonMessageInterface as ChatActivity val message = chatMessage.message!!.toSpanned() val messageTextView = binding.messageText val checkBoxContainer = binding.checkboxContainer + val isOlderThanTwentyFourHours = chatMessage + .createdAt + .before(Date(System.currentTimeMillis() - AGE_THRESHOLD_FOR_EDIT_MESSAGE)) checkBoxContainer.removeAllViews() val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) @@ -178,6 +182,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : val checkBox = CheckBox(checkBoxContainer.context).apply { text = taskText this.isChecked = isChecked + this.isEnabled = !isOlderThanTwentyFourHours && chatMessage.actorType == "bots" || chatActivity + .userAllowedByPrivilages(chatMessage) setOnCheckedChangeListener { _, _ -> updateCheckboxStates(chatMessage, user, checkboxList) } @@ -186,7 +192,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : checkboxList.add(checkBox) viewThemeUtils.platform.themeCheckbox(checkBox) } - checkBoxContainer.visibility = View.VISIBLE return true } @@ -347,5 +352,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : private val TAG = IncomingTextMessageViewHolder::class.java.simpleName private const val CHECKED_GROUP_INDEX = 2 private const val TASK_TEXT_GROUP_INDEX = 3 + private const val AGE_THRESHOLD_FOR_EDIT_MESSAGE: Long = 86400000 } } 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 907b3cd1d..6e54d5259 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 @@ -13,31 +13,39 @@ import android.content.Context import android.util.Log import android.util.TypedValue import android.view.View +import android.widget.CheckBox import androidx.core.content.res.ResourcesCompat +import androidx.core.text.toSpanned import androidx.lifecycle.lifecycleScope import autodagger.AutoInjector import coil.load import com.google.android.flexbox.FlexboxLayout +import com.google.android.material.snackbar.Snackbar import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.chat.ChatActivity +import com.nextcloud.talk.chat.data.ChatMessageRepository import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.data.network.NetworkMonitor +import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ItemCustomOutcomingTextMessageBinding import com.nextcloud.talk.models.json.chat.ReadStatus import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.TextMatchers +import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.message.MessageUtils import com.stfalcon.chatkit.messages.MessageHolders.OutcomingTextMessageViewHolder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.util.Date import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -65,30 +73,32 @@ class OutcomingTextMessageViewHolder(itemView: View) : lateinit var commonMessageInterface: CommonMessageInterface + @Inject + lateinit var chatRepository: ChatMessageRepository + + @Inject + lateinit var currentUserProvider: CurrentUserProviderNew + + private var job: Job? = null + @Suppress("Detekt.LongMethod") override fun onBind(message: ChatMessage) { super.onBind(message) sharedApplication!!.componentApplication.inject(this) + val user = currentUserProvider.currentUser.blockingGet() + val hasCheckboxes = processCheckboxes( + message, + user + ) + processMessage(message, hasCheckboxes) + } + + private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) { realView.isSelected = false val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams layoutParams.isWrapBefore = false - var textSize = context.resources.getDimension(R.dimen.chat_text_size) viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT) - - var processedMessageText = messageUtils.enrichChatMessageText( - binding.messageText.context, - message, - false, - viewThemeUtils - ) - processedMessageText = messageUtils.processMessageParameters( - binding.messageText.context, - viewThemeUtils, - processedMessageText!!, - message, - itemView - ) - + var textSize = context.resources.getDimension(R.dimen.chat_text_size) var isBubbled = true if ( (message.messageParameters == null || message.messageParameters!!.size <= 0) && @@ -105,7 +115,25 @@ class OutcomingTextMessageViewHolder(itemView: View) : binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageTime.layoutParams = layoutParams viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT) - binding.messageText.text = processedMessageText + + if (!hasCheckboxes) { + var processedMessageText = messageUtils.enrichChatMessageText( + binding.messageText.context, + message, + false, + viewThemeUtils + ) + processedMessageText = messageUtils.processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) + binding.messageText.text = processedMessageText + }else{ + binding.messageText.text = "" + } if (message.lastEditTimestamp != 0L && !message.isDeleted) { binding.messageEditIndicator.visibility = View.VISIBLE @@ -161,6 +189,94 @@ class OutcomingTextMessageViewHolder(itemView: View) : ) } + private fun processCheckboxes(chatMessage: ChatMessage, user: User): Boolean { + val message = chatMessage.message!!.toSpanned() + val messageTextView = binding.messageText + val checkBoxContainer = binding.checkboxContainer + val isOlderThanTwentyFourHours = chatMessage + .createdAt + .before(Date(System.currentTimeMillis() - AGE_THRESHOLD_FOR_EDIT_MESSAGE)) + + checkBoxContainer.removeAllViews() + val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) + val matches = regex.findAll(message) + + if (matches.none()) return false + + val firstPart = message.toString().substringBefore("\n- [") + messageTextView.text = messageUtils.enrichChatMessageText( + binding.messageText.context, firstPart, true, viewThemeUtils + ) + + val checkboxList = mutableListOf() + + matches.forEach { matchResult -> + val isChecked = matchResult.groupValues[CHECKED_GROUP_INDEX] == "X" || + matchResult.groupValues[CHECKED_GROUP_INDEX] == "x" + val taskText = matchResult.groupValues[TASK_TEXT_GROUP_INDEX].trim() + + val checkBox = CheckBox(checkBoxContainer.context).apply { + text = taskText + this.isChecked = isChecked + this.isEnabled = !isOlderThanTwentyFourHours + setOnCheckedChangeListener { _, _ -> + updateCheckboxStates(chatMessage, user, checkboxList) + } + } + checkBoxContainer.addView(checkBox) + checkboxList.add(checkBox) + viewThemeUtils.platform.themeCheckbox(checkBox) + } + + checkBoxContainer.visibility = View.VISIBLE + return true + } + + private fun updateCheckboxStates(chatMessage: ChatMessage, user: User, checkboxes: List) { + job = CoroutineScope(Dispatchers.Main).launch { + withContext(Dispatchers.IO) { + val apiVersion: Int = ApiUtils.getChatApiVersion( + user.capabilities?.spreedCapability!!, + intArrayOf(1) + ) + val updatedMessage = updateMessageWithCheckboxStates(chatMessage.message!!, checkboxes) + chatRepository.editChatMessage( + user.getCredentials(), + ApiUtils.getUrlForChatMessage(apiVersion, user.baseUrl!!, chatMessage.token!!, chatMessage.id), + updatedMessage + ).collect { result -> + withContext(Dispatchers.Main) { + if (result.isSuccess) { + val editedMessage = result.getOrNull()?.ocs?.data!!.parentMessage!! + Log.d(TAG, "EditedMessage: $editedMessage") + binding.messageEditIndicator.apply { + visibility = View.VISIBLE + } + binding.messageTime.text = + dateUtils.getLocalTimeStringFromTimestamp(editedMessage.lastEditTimestamp!!) + } else { + Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() + } + } + } + } + } + } + + private fun updateMessageWithCheckboxStates(originalMessage: String, checkboxes: List): String { + var updatedMessage = originalMessage + val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) + + checkboxes.forEach { checkBox -> + updatedMessage = regex.replace(updatedMessage) { matchResult -> + val taskText = matchResult.groupValues[TASK_TEXT_GROUP_INDEX].trim() + val checkboxState = if (checkboxes.find { it.text == taskText }?.isChecked == true) "X" else " " + "- [$checkboxState] $taskText" + } + } + return updatedMessage + } + private fun updateStatus(readStatusDrawableInt: Int, description: String?) { binding.sendingProgress.visibility = View.GONE binding.checkMark.visibility = View.VISIBLE @@ -248,5 +364,8 @@ class OutcomingTextMessageViewHolder(itemView: View) : companion object { const val TEXT_SIZE_MULTIPLIER = 2.5 private val TAG = OutcomingTextMessageViewHolder::class.java.simpleName + private const val CHECKED_GROUP_INDEX = 2 + private const val TASK_TEXT_GROUP_INDEX = 3 + private const val AGE_THRESHOLD_FOR_EDIT_MESSAGE: Long = 86400000 } } diff --git a/app/src/main/res/layout/item_custom_outcoming_text_message.xml b/app/src/main/res/layout/item_custom_outcoming_text_message.xml index ec70f5e47..ffe06be8b 100644 --- a/app/src/main/res/layout/item_custom_outcoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_outcoming_text_message.xml @@ -43,6 +43,17 @@ android:textIsSelectable="false" tools:text="Talk to you later!" /> + + + + Date: Thu, 13 Mar 2025 17:01:56 +0100 Subject: [PATCH 11/15] modify outgoingTextViewHolder Signed-off-by: sowjanyakch --- .../OutcomingTextMessageViewHolder.kt | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) 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 6e54d5259..5f25c44d7 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 @@ -94,29 +94,14 @@ class OutcomingTextMessageViewHolder(itemView: View) : } private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) { - realView.isSelected = false - val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams - layoutParams.isWrapBefore = false - viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT) - var textSize = context.resources.getDimension(R.dimen.chat_text_size) var isBubbled = true - if ( - (message.messageParameters == null || message.messageParameters!!.size <= 0) && - TextMatchers.isMessageWithSingleEmoticonOnly(message.text) - ) { - textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat() - layoutParams.isWrapBefore = true - realView.isSelected = true - isBubbled = false - } - - setBubbleOnChatMessage(message) - - binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - binding.messageTime.layoutParams = layoutParams - viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT) - if (!hasCheckboxes) { + realView.isSelected = false + val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams + layoutParams.isWrapBefore = false + var textSize = context.resources.getDimension(R.dimen.chat_text_size) + viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT) + var processedMessageText = messageUtils.enrichChatMessageText( binding.messageText.context, message, @@ -130,7 +115,22 @@ class OutcomingTextMessageViewHolder(itemView: View) : message, itemView ) + + if ( + (message.messageParameters == null || message.messageParameters!!.size <= 0) && + TextMatchers.isMessageWithSingleEmoticonOnly(message.text) + ) { + textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat() + layoutParams.isWrapBefore = true + realView.isSelected = true + isBubbled = false + } + + binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + binding.messageTime.layoutParams = layoutParams + viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT) binding.messageText.text = processedMessageText + }else{ binding.messageText.text = "" } @@ -142,7 +142,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : binding.messageEditIndicator.visibility = View.GONE binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) } - + setBubbleOnChatMessage(message) // parent message handling if (!message.isDeleted && message.parentMessageId != null) { processParentMessage(message) From ea61e4982141d8536f759cf08c8c249187157f91 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Thu, 13 Mar 2025 17:54:54 +0100 Subject: [PATCH 12/15] layout changes Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 14 +++++++++++-- .../OutcomingTextMessageViewHolder.kt | 20 +++++++++++++------ .../item_custom_incoming_text_message.xml | 10 +++++----- .../item_custom_outcoming_text_message.xml | 11 +++++----- 4 files changed, 36 insertions(+), 19 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 c1a22a94e..fe912684e 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 @@ -92,6 +92,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) { var textSize = context.resources!!.getDimension(R.dimen.chat_text_size) if (!hasCheckboxes) { + binding.messageText.visibility = View.VISIBLE + binding.checkboxContainer.visibility = View.GONE var processedMessageText = messageUtils.enrichChatMessageText( binding.messageText.context, message, @@ -121,7 +123,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageText.text = processedMessageText }else{ - binding.messageText.text = "" + binding.messageText.visibility = View.GONE + binding.checkboxContainer.visibility = View.VISIBLE } if (message.lastEditTimestamp != 0L && !message.isDeleted) { @@ -233,7 +236,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : var updatedMessage = originalMessage val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) - checkboxes.forEach { checkBox -> + checkboxes.forEach { _ -> updatedMessage = regex.replace(updatedMessage) { matchResult -> val taskText = matchResult.groupValues[TASK_TEXT_GROUP_INDEX].trim() val checkboxState = if (checkboxes.find { it.text == taskText }?.isChecked == true) "X" else " " @@ -347,6 +350,11 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : this.commonMessageInterface = commonMessageInterface } + override fun viewDetached() { + super.viewDetached() + job?.cancel() + } + companion object { const val TEXT_SIZE_MULTIPLIER = 2.5 private val TAG = IncomingTextMessageViewHolder::class.java.simpleName @@ -355,3 +363,5 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : private const val AGE_THRESHOLD_FOR_EDIT_MESSAGE: Long = 86400000 } } + + 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 5f25c44d7..98f51f880 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 @@ -95,13 +95,16 @@ class OutcomingTextMessageViewHolder(itemView: View) : private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) { var isBubbled = true + val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams + var textSize = context.resources.getDimension(R.dimen.chat_text_size) if (!hasCheckboxes) { realView.isSelected = false - val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams layoutParams.isWrapBefore = false - var textSize = context.resources.getDimension(R.dimen.chat_text_size) viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT) + binding.messageText.visibility = View.VISIBLE + binding.checkboxContainer.visibility = View.GONE + var processedMessageText = messageUtils.enrichChatMessageText( binding.messageText.context, message, @@ -126,15 +129,15 @@ class OutcomingTextMessageViewHolder(itemView: View) : isBubbled = false } - binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageTime.layoutParams = layoutParams viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT) binding.messageText.text = processedMessageText }else{ - binding.messageText.text = "" + binding.messageText.visibility = View.GONE + binding.checkboxContainer.visibility = View.VISIBLE } - + binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) if (message.lastEditTimestamp != 0L && !message.isDeleted) { binding.messageEditIndicator.visibility = View.VISIBLE binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.lastEditTimestamp!!) @@ -267,7 +270,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : var updatedMessage = originalMessage val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) - checkboxes.forEach { checkBox -> + checkboxes.forEach { _ -> updatedMessage = regex.replace(updatedMessage) { matchResult -> val taskText = matchResult.groupValues[TASK_TEXT_GROUP_INDEX].trim() val checkboxState = if (checkboxes.find { it.text == taskText }?.isChecked == true) "X" else " " @@ -361,6 +364,11 @@ class OutcomingTextMessageViewHolder(itemView: View) : this.commonMessageInterface = commonMessageInterface } + override fun viewDetached() { + super.viewDetached() + job?.cancel() + } + companion object { const val TEXT_SIZE_MULTIPLIER = 2.5 private val TAG = OutcomingTextMessageViewHolder::class.java.simpleName diff --git a/app/src/main/res/layout/item_custom_incoming_text_message.xml b/app/src/main/res/layout/item_custom_incoming_text_message.xml index 884c3087d..b025cc40f 100644 --- a/app/src/main/res/layout/item_custom_incoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_text_message.xml @@ -67,11 +67,12 @@ - + android:layout_below="@id/messageText" + android:layout_marginBottom="8dp" + android:visibility="gone"> diff --git a/app/src/main/res/layout/item_custom_outcoming_text_message.xml b/app/src/main/res/layout/item_custom_outcoming_text_message.xml index ffe06be8b..52f2671a4 100644 --- a/app/src/main/res/layout/item_custom_outcoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_outcoming_text_message.xml @@ -41,15 +41,17 @@ android:textAlignment="viewStart" android:textColorHighlight="@color/nc_grey" android:textIsSelectable="false" + app:layout_alignSelf="flex_start" + app:layout_flexGrow="1" tools:text="Talk to you later!" /> @@ -65,7 +67,6 @@ android:textColor="@color/no_emphasis_text" android:textIsSelectable="false" app:layout_alignSelf="flex_end" - android:layout_gravity="end" app:layout_flexGrow="1" app:layout_wrapBefore="false" tools:text="10:35" /> @@ -79,7 +80,6 @@ android:alpha="0.6" android:textColor="@color/no_emphasis_text" android:textIsSelectable="false" - android:gravity="end" app:layout_alignSelf="flex_end" android:text = "@string/hint_edited_message" android:textSize="12sp"> @@ -94,7 +94,6 @@ android:layout_marginStart="8dp" android:contentDescription="@null" app:layout_alignSelf="flex_end" - android:gravity="end" app:tint="@color/high_emphasis_text" tools:src="@drawable/ic_check_all" /> @@ -105,7 +104,7 @@ android:layout_below="@id/messageTime" android:layout_marginStart="8dp" android:contentDescription="@null" - app:layout_alignSelf="center" + app:layout_alignSelf="flex_end" app:tint="@color/high_emphasis_text" tools:src="@drawable/ic_warning_white"/> From 68efcc0a95ebee7475a1de8094dd7bc69d45cc33 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Mon, 17 Mar 2025 15:29:08 +0100 Subject: [PATCH 13/15] check for necessary capabilities Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 18 +++++++++------- .../OutcomingTextMessageViewHolder.kt | 21 ++++++++++++++----- 2 files changed, 27 insertions(+), 12 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 fe912684e..b3c428611 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 @@ -28,8 +28,10 @@ import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability import com.nextcloud.talk.utils.ChatMessageUtils import com.nextcloud.talk.utils.DateUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.TextMatchers import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.message.MessageUtils @@ -121,8 +123,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.text = processedMessageText - - }else{ + } else { binding.messageText.visibility = View.GONE binding.checkboxContainer.visibility = View.VISIBLE } @@ -164,6 +165,12 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : .createdAt .before(Date(System.currentTimeMillis() - AGE_THRESHOLD_FOR_EDIT_MESSAGE)) + val messageIsEditable = hasSpreedFeatureCapability( + user.capabilities?.spreedCapability!!, + SpreedFeatures.EDIT_MESSAGES + ) && + !isOlderThanTwentyFourHours + checkBoxContainer.removeAllViews() val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) val matches = regex.findAll(message) @@ -185,8 +192,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : val checkBox = CheckBox(checkBoxContainer.context).apply { text = taskText this.isChecked = isChecked - this.isEnabled = !isOlderThanTwentyFourHours && chatMessage.actorType == "bots" || chatActivity - .userAllowedByPrivilages(chatMessage) + this.isEnabled = (chatMessage.actorType == "bots" || + chatActivity.userAllowedByPrivilages(chatMessage)) && messageIsEditable setOnCheckedChangeListener { _, _ -> updateCheckboxStates(chatMessage, user, checkboxList) } @@ -195,7 +202,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : checkboxList.add(checkBox) viewThemeUtils.platform.themeCheckbox(checkBox) } - checkBoxContainer.visibility = View.VISIBLE return true } @@ -206,9 +212,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : user.capabilities?.spreedCapability!!, intArrayOf(1) ) - val updatedMessage = updateMessageWithCheckboxStates(chatMessage.message!!, checkboxes) - chatRepository.editChatMessage( user.getCredentials(), ApiUtils.getUrlForChatMessage(apiVersion, user.baseUrl!!, chatMessage.token!!, chatMessage.id), 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 98f51f880..441c70917 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 @@ -32,9 +32,12 @@ import com.nextcloud.talk.data.network.NetworkMonitor import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ItemCustomOutcomingTextMessageBinding import com.nextcloud.talk.models.json.chat.ReadStatus +import com.nextcloud.talk.models.json.conversations.ConversationEnums import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability import com.nextcloud.talk.utils.DateUtils +import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.TextMatchers import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.message.MessageUtils @@ -132,8 +135,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : binding.messageTime.layoutParams = layoutParams viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT) binding.messageText.text = processedMessageText - - }else{ + } else { binding.messageText.visibility = View.GONE binding.checkboxContainer.visibility = View.VISIBLE } @@ -193,12 +195,23 @@ class OutcomingTextMessageViewHolder(itemView: View) : } private fun processCheckboxes(chatMessage: ChatMessage, user: User): Boolean { + val chatActivity = commonMessageInterface as ChatActivity val message = chatMessage.message!!.toSpanned() val messageTextView = binding.messageText val checkBoxContainer = binding.checkboxContainer val isOlderThanTwentyFourHours = chatMessage .createdAt .before(Date(System.currentTimeMillis() - AGE_THRESHOLD_FOR_EDIT_MESSAGE)) + val messageIsEditable = hasSpreedFeatureCapability( + user.capabilities?.spreedCapability!!, + SpreedFeatures.EDIT_MESSAGES + ) && !isOlderThanTwentyFourHours + + val isNoTimeLimitOnNoteToSelf = hasSpreedFeatureCapability( + user.capabilities?.spreedCapability!!, + SpreedFeatures + .EDIT_MESSAGES_NOTE_TO_SELF + ) && chatActivity.currentConversation?.type == ConversationEnums.ConversationType.NOTE_TO_SELF checkBoxContainer.removeAllViews() val regex = """(- \[(X|x| )])\s*(.+)""".toRegex(RegexOption.MULTILINE) @@ -221,7 +234,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : val checkBox = CheckBox(checkBoxContainer.context).apply { text = taskText this.isChecked = isChecked - this.isEnabled = !isOlderThanTwentyFourHours + this.isEnabled = messageIsEditable || isNoTimeLimitOnNoteToSelf setOnCheckedChangeListener { _, _ -> updateCheckboxStates(chatMessage, user, checkboxList) } @@ -230,8 +243,6 @@ class OutcomingTextMessageViewHolder(itemView: View) : checkboxList.add(checkBox) viewThemeUtils.platform.themeCheckbox(checkBox) } - - checkBoxContainer.visibility = View.VISIBLE return true } From 52cb8374386fba6a6c83d8fbed6a2334cc21bdaa Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Mon, 17 Mar 2025 16:07:36 +0100 Subject: [PATCH 14/15] fix detekt Signed-off-by: sowjanyakch --- .../messages/IncomingTextMessageViewHolder.kt | 11 ++++------- .../messages/OutcomingTextMessageViewHolder.kt | 1 + 2 files changed, 5 insertions(+), 7 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 b3c428611..b8ddd83bf 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 @@ -102,7 +102,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : true, viewThemeUtils ) - processedMessageText = messageUtils.processMessageParameters( binding.messageText.context, viewThemeUtils, @@ -110,7 +109,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : message, itemView ) - val messageParameters = message.messageParameters if ( (messageParameters == null || messageParameters.size <= 0) && @@ -120,7 +118,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : itemView.isSelected = true binding.messageAuthor.visibility = View.GONE } - binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) binding.messageText.text = processedMessageText } else { @@ -192,8 +189,10 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : val checkBox = CheckBox(checkBoxContainer.context).apply { text = taskText this.isChecked = isChecked - this.isEnabled = (chatMessage.actorType == "bots" || - chatActivity.userAllowedByPrivilages(chatMessage)) && messageIsEditable + this.isEnabled = ( + chatMessage.actorType == "bots" || + chatActivity.userAllowedByPrivilages(chatMessage) + ) && messageIsEditable setOnCheckedChangeListener { _, _ -> updateCheckboxStates(chatMessage, user, checkboxList) } @@ -367,5 +366,3 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : private const val AGE_THRESHOLD_FOR_EDIT_MESSAGE: Long = 86400000 } } - - 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 441c70917..8c0e809d3 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 @@ -96,6 +96,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : processMessage(message, hasCheckboxes) } + @Suppress("Detekt.LongMethod") private fun processMessage(message: ChatMessage, hasCheckboxes: Boolean) { var isBubbled = true val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams From 0e38490ea60806b9bbfe86d97af02b3b925d5e05 Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 21 Mar 2025 16:57:01 +0100 Subject: [PATCH 15/15] fix theming Signed-off-by: sowjanyakch --- .../talk/adapters/messages/IncomingTextMessageViewHolder.kt | 5 +++++ .../talk/adapters/messages/OutcomingTextMessageViewHolder.kt | 5 +++++ 2 files changed, 10 insertions(+) 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 b8ddd83bf..5636cc1de 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 @@ -14,6 +14,7 @@ import android.util.Log import android.util.TypedValue import android.view.View import android.widget.CheckBox +import androidx.core.content.ContextCompat import androidx.core.text.toSpanned import autodagger.AutoInjector import coil.load @@ -132,6 +133,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageEditIndicator.visibility = View.GONE binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) } + binding.messageTime.setTextColor(ContextCompat.getColor(context, R.color.no_emphasis_text)) // parent message handling if (!message.isDeleted && message.parentMessageId != null) { processParentMessage(message) @@ -193,6 +195,9 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : chatMessage.actorType == "bots" || chatActivity.userAllowedByPrivilages(chatMessage) ) && messageIsEditable + + setTextColor(ContextCompat.getColor(context, R.color.no_emphasis_text)) + setOnCheckedChangeListener { _, _ -> updateCheckboxStates(chatMessage, user, checkboxList) } 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 8c0e809d3..ae6caa30b 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 @@ -14,6 +14,7 @@ import android.util.Log import android.util.TypedValue import android.view.View import android.widget.CheckBox +import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.text.toSpanned import androidx.lifecycle.lifecycleScope @@ -148,6 +149,7 @@ class OutcomingTextMessageViewHolder(itemView: View) : binding.messageEditIndicator.visibility = View.GONE binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) } + binding.messageTime.setTextColor(ContextCompat.getColor(context, R.color.no_emphasis_text)) setBubbleOnChatMessage(message) // parent message handling if (!message.isDeleted && message.parentMessageId != null) { @@ -236,6 +238,9 @@ class OutcomingTextMessageViewHolder(itemView: View) : text = taskText this.isChecked = isChecked this.isEnabled = messageIsEditable || isNoTimeLimitOnNoteToSelf + + setTextColor(ContextCompat.getColor(context, R.color.no_emphasis_text)) + setOnCheckedChangeListener { _, _ -> updateCheckboxStates(chatMessage, user, checkboxList) }