diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java index b9185c7aa..581d3ebb7 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/TalkMessagesListAdapter.java @@ -65,6 +65,8 @@ public class TalkMessagesListAdapter extends MessagesListAda ((SystemMessageViewHolder) holder).assignSystemMessageInterface(chatActivity); } else if (holder instanceof CallStartedViewHolder) { ((CallStartedViewHolder) holder).assignCallStartedMessageInterface(chatActivity); + } else if (holder instanceof TemporaryMessageViewHolder) { + ((TemporaryMessageViewHolder) holder).assignTemporaryMessageInterface(chatActivity); } super.onBindViewHolder(holder, position); diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageInterface.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageInterface.kt new file mode 100644 index 000000000..353aa4471 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageInterface.kt @@ -0,0 +1,13 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Your Name + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.adapters.messages + +interface TemporaryMessageInterface { + fun editTemporaryMessage(id: Int, newMessage: String) + fun deleteTemporaryMessage(id: Int) +} diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageViewHolder.kt index e55fd24bb..2a2173460 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/TemporaryMessageViewHolder.kt @@ -11,6 +11,7 @@ import android.view.View import androidx.core.content.res.ResourcesCompat import androidx.core.view.ViewCompat import autodagger.AutoInjector +import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.chat.data.model.ChatMessage @@ -29,10 +30,23 @@ class TemporaryMessageViewHolder(outgoingView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils - override fun onBind(message: ChatMessage?) { + lateinit var temporaryMessageInterface: TemporaryMessageInterface + + override fun onBind(message: ChatMessage) { super.onBind(message) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) + viewThemeUtils.platform.colorImageView(binding.tempMsgEdit, ColorRole.PRIMARY) + viewThemeUtils.platform.colorImageView(binding.tempMsgDelete, ColorRole.PRIMARY) + + binding.tempMsgEdit.setOnClickListener { + // TODO + } + + binding.tempMsgDelete.setOnClickListener { + temporaryMessageInterface.deleteTemporaryMessage(message.tempMessageId) + } + val bgBubbleColor = bubble.resources.getColor(R.color.bg_message_list_incoming_bubble, null) val layout = R.drawable.shape_outcoming_message val bubbleDrawable = DisplayUtils.getMessageSelector( @@ -45,6 +59,10 @@ class TemporaryMessageViewHolder(outgoingView: View, payload: Any) : } + fun assignTemporaryMessageInterface(temporaryMessageInterface: TemporaryMessageInterface) { + this.temporaryMessageInterface = temporaryMessageInterface + } + override fun viewDetached() { // unused atm } 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 a692da94a..54af54cb7 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -101,6 +101,7 @@ import com.nextcloud.talk.adapters.messages.PreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.SystemMessageInterface import com.nextcloud.talk.adapters.messages.SystemMessageViewHolder import com.nextcloud.talk.adapters.messages.TalkMessagesListAdapter +import com.nextcloud.talk.adapters.messages.TemporaryMessageInterface import com.nextcloud.talk.adapters.messages.TemporaryMessageViewHolder import com.nextcloud.talk.adapters.messages.UnreadNoticeMessageViewHolder import com.nextcloud.talk.adapters.messages.VoiceMessageInterface @@ -214,7 +215,8 @@ class ChatActivity : CommonMessageInterface, PreviewMessageInterface, SystemMessageInterface, - CallStartedMessageInterface { + CallStartedMessageInterface, + TemporaryMessageInterface { var active = false @@ -536,13 +538,15 @@ class ChatActivity : Log.d(TAG, "initObservers Called") messageInputViewModel.messageQueueFlow.observe(this) { list -> - for (message in list) { - Log.d("Julius", "Message recieved: $message") + list.forEachIndexed { _, qMsg -> + Log.d("Julius", "Message recieved: ${qMsg.message}") val temporaryChatMessage = ChatMessage() temporaryChatMessage.jsonMessageId = -3 temporaryChatMessage.actorId = "-3" temporaryChatMessage.timestamp = System.currentTimeMillis() / 1000 - temporaryChatMessage.message = message + temporaryChatMessage.message = qMsg.message.toString() + temporaryChatMessage.tempMessageId = qMsg.id + temporaryChatMessage.isTempMessage = true adapter?.addToStart(temporaryChatMessage, true) } } @@ -3103,7 +3107,10 @@ class ChatActivity : private fun openMessageActionsDialog(iMessage: IMessage?) { val message = iMessage as ChatMessage - if (hasVisibleItems(message) && !isSystemMessage(message)) { + if (hasVisibleItems(message) && + !isSystemMessage(message) && + message.id != "-3" + ) { MessageActionsDialog( this, message, @@ -3658,6 +3665,29 @@ class ChatActivity : startACall(false, false) } + override fun editTemporaryMessage(id: Int, newMessage: String) { + // TODO("Not yet implemented") + } + + override fun deleteTemporaryMessage(id: Int) { + messageInputViewModel.removeFromQueue(roomToken, id) + var i = 0 + val max = messageInputViewModel.messageQueueSizeFlow.value?.plus(1) + for (item in adapter?.items!!) { // add limit? + if (i >= max!!) break + if (item.item is ChatMessage && + (item.item as ChatMessage).isTempMessage && + (item.item as ChatMessage).tempMessageId == id + ) { + val index = adapter?.items!!.indexOf(item) + adapter?.items!!.removeAt(index) + adapter?.notifyItemRemoved(index) + break + } + i++ + } + } + private fun logConversationInfos(methodName: String) { Log.d(TAG, " |-----------------------------------------------") Log.d(TAG, " | method: $methodName") diff --git a/app/src/main/java/com/nextcloud/talk/chat/data/model/ChatMessage.kt b/app/src/main/java/com/nextcloud/talk/chat/data/model/ChatMessage.kt index 2c3bf7dad..cc3cbec92 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/data/model/ChatMessage.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/data/model/ChatMessage.kt @@ -111,7 +111,11 @@ data class ChatMessage( var hiddenByCollapse: Boolean = false, - var openWhenDownloaded: Boolean = true + var openWhenDownloaded: Boolean = true, + + var isTempMessage: Boolean = false, + + var tempMessageId: Int = -1 ) : MessageContentType, MessageContentType.Image { diff --git a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt index 9c408724e..75a10a9c8 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt @@ -48,6 +48,7 @@ class MessageInputViewModel @Inject constructor( val disposableSet = mutableSetOf() data class QueuedMessage( + val id: Int, val message: CharSequence? = null, val displayName: String? = null, val replyTo: Int? = null, @@ -124,8 +125,8 @@ class MessageInputViewModel @Inject constructor( val messageQueueSizeFlow: LiveData get() = _messageQueueSizeFlow.asLiveData() - private val _messageQueueFlow: MutableLiveData> = MutableLiveData() - val messageQueueFlow: LiveData> + private val _messageQueueFlow: MutableLiveData> = MutableLiveData() + val messageQueueFlow: LiveData> get() = _messageQueueFlow @Suppress("LongParameterList") @@ -139,10 +140,12 @@ class MessageInputViewModel @Inject constructor( sendWithoutNotification: Boolean ) { if (isQueueing) { - messageQueue.add(QueuedMessage(message, displayName, replyTo, sendWithoutNotification)) + val tempID = System.currentTimeMillis().toInt() + val qMsg = QueuedMessage(tempID, message, displayName, replyTo, sendWithoutNotification) + messageQueue.add(qMsg) dataStore.saveMessageQueue(roomToken, messageQueue) _messageQueueSizeFlow.update { messageQueue.size } - _messageQueueFlow.postValue(listOf(message.toString())) + _messageQueueFlow.postValue(listOf(qMsg)) return } @@ -271,10 +274,10 @@ class MessageInputViewModel @Inject constructor( fun getTempMessagesFromMessageQueue(roomToken: String) { val queue = dataStore.getMessageQueue(roomToken) - val list = mutableListOf() + val list = mutableListOf() for (msg in queue) { Log.d("Julius", "Msg: ${msg.message}") - list.add(msg.message.toString()) + list.add(msg) } _messageQueueFlow.postValue(list) } @@ -288,6 +291,18 @@ class MessageInputViewModel @Inject constructor( _messageQueueSizeFlow.tryEmit(messageQueue.size) } + fun removeFromQueue(roomToken: String, id: Int) { + val queue = dataStore.getMessageQueue(roomToken) + for (qMsg in queue) { + if (qMsg.id == id) { + queue.remove(qMsg) + break + } + } + dataStore.saveMessageQueue(roomToken, queue) + _messageQueueSizeFlow.tryEmit(queue.size) + } + companion object { private val TAG = MessageInputViewModel::class.java.simpleName private const val DELAY_BETWEEN_QUEUED_MESSAGES: Long = 100 diff --git a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt index b1b948bbd..8cde1c64c 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt @@ -484,7 +484,10 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { var queueStr = "" queue?.let { for (msg in queue) { - val msgStr = "${msg.message},${msg.replyTo},${msg.displayName},${msg.sendWithoutNotification}^" + val msgStr = "${msg.id},${msg.message},${msg.replyTo},${msg.displayName},${ + msg + .sendWithoutNotification + }^" queueStr += msgStr } } @@ -504,12 +507,13 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { try { if (msgStr.isNotEmpty()) { val msgArray = msgStr.split(",") + val id = msgArray[ID].toInt() val message = msgArray[MESSAGE_INDEX] val replyTo = msgArray[REPLY_TO_INDEX].toInt() - val displayName = msgArray[DISPLY_NAME_INDEX] + val displayName = msgArray[DISPLAY_NAME_INDEX] val silent = msgArray[SILENT_INDEX].toBoolean() - val qMsg = MessageInputViewModel.QueuedMessage(message, displayName, replyTo, silent) + val qMsg = MessageInputViewModel.QueuedMessage(id, message, displayName, replyTo, silent) queue.add(qMsg) } } catch (e: IndexOutOfBoundsException) { @@ -572,10 +576,11 @@ class AppPreferencesImpl(val context: Context) : AppPreferences { @Suppress("UnusedPrivateProperty") private val TAG = AppPreferencesImpl::class.simpleName private val Context.dataStore: DataStore by preferencesDataStore(name = "settings") - private const val MESSAGE_INDEX: Int = 0 - private const val REPLY_TO_INDEX: Int = 1 - private const val DISPLY_NAME_INDEX: Int = 2 - private const val SILENT_INDEX: Int = 3 + private const val ID: Int = 0 + private const val MESSAGE_INDEX: Int = 1 + private const val REPLY_TO_INDEX: Int = 2 + private const val DISPLAY_NAME_INDEX: Int = 3 + private const val SILENT_INDEX: Int = 4 const val PROXY_TYPE = "proxy_type" const val PROXY_SERVER = "proxy_server" const val PROXY_HOST = "proxy_host" diff --git a/app/src/main/res/layout/item_temporary_message.xml b/app/src/main/res/layout/item_temporary_message.xml index 82fb3bb54..532ae7ab9 100644 --- a/app/src/main/res/layout/item_temporary_message.xml +++ b/app/src/main/res/layout/item_temporary_message.xml @@ -15,13 +15,28 @@ android:layout_marginRight="16dp" android:layout_marginBottom="2dp"> - + android:orientation="horizontal" + android:layout_centerVertical="true"> + + + + +