mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 11:39:42 +01:00
edit checkbox messages directly
Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
This commit is contained in:
parent
4abb28e445
commit
8b44882e78
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<CheckBox>()
|
||||
|
||||
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<CheckBox>) {
|
||||
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<CheckBox>): 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
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,17 @@
|
||||
android:textIsSelectable="false"
|
||||
tools:text="Talk to you later!" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/checkboxContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_below="@id/messageText"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@id/messageTime"
|
||||
android:layout_width="wrap_content"
|
||||
|
Loading…
Reference in New Issue
Block a user