From 751016617ceb9b70e17f27ba980b4f35607647c5 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Tue, 23 Jul 2024 10:26:00 +1000 Subject: [PATCH] Adding the ability to customise the text for the deleted control messages --- .../attachments/DatabaseAttachmentProvider.kt | 25 ++++++++++--------- .../conversation/v2/ConversationActivityV2.kt | 5 +++- .../conversation/v2/ConversationViewModel.kt | 14 +++++------ .../v2/messages/DeletedMessageView.kt | 3 ++- .../securesms/database/MessagingDatabase.java | 2 +- .../securesms/database/MmsDatabase.kt | 4 +-- .../securesms/database/SmsDatabase.java | 4 +-- .../repository/ConversationRepository.kt | 14 ++++++++--- .../v2/ConversationViewModelTest.kt | 3 +-- .../database/MessageDataProvider.kt | 4 +-- .../ReceivedMessageHandler.kt | 6 ++++- 11 files changed, 49 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt index d2dd921128..ac213edc97 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt @@ -216,33 +216,34 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper) threadId?.let{ MessagingModuleConfiguration.shared.lastSentTimestampCache.delete(it, messages.map { it.timestamp }) } } - override fun updateMessageAsDeleted(timestamp: Long, author: String): Long? { + override fun markMessageAsDeleted(timestamp: Long, author: String, displayedMessage: String): Long? { val database = DatabaseComponent.get(context).mmsSmsDatabase() val address = Address.fromSerialized(author) val message = database.getMessageFor(timestamp, address) ?: return null - val messagingDatabase: MessagingDatabase = if (message.isMms) DatabaseComponent.get(context).mmsDatabase() - else DatabaseComponent.get(context).smsDatabase() - messagingDatabase.markAsDeleted(message.id, message.isOutgoing) - if (message.isOutgoing) { - messagingDatabase.deleteMessage(message.id) - } -//todo DELETION might need to change this with new logic + markMessagesAsDeleted( + messages = listOf(MarkAsDeletedMessage( + messageId = message.id, + isOutgoing = message.isOutgoing + )), + isSms = !message.isMms, + displayedMessage = displayedMessage + ) + return message.id } override fun markMessagesAsDeleted( messages: List, - threadId: Long, - isSms: Boolean + isSms: Boolean, + displayedMessage: String ) { val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase() else DatabaseComponent.get(context).mmsDatabase() //todo DELETION can this be batched? - //todo DELETION we need to have customisable text for "marked as deleted" message messages.forEach { message -> - messagingDatabase.markAsDeleted(message.messageId, message.isOutgoing) + messagingDatabase.markAsDeleted(message.messageId, message.isOutgoing, displayedMessage) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 38b63b039b..b4d806ac34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1968,7 +1968,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // creating a reusable callback val deleteDeviceOnly = { - viewModel.markAsDeletedLocally(messages = messages, threadId = viewModel.threadId) + viewModel.markAsDeletedLocally( + messages = messages, + displayedMessage = "[UPDATE THIS!] This message was deleted on this device" //todo DELETION update once we have strings + ) endActionMode() //todo DELETION show confirmation toast } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt index 9d0fd05e16..2711820fc2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt @@ -38,8 +38,7 @@ class ConversationViewModel( val edKeyPair: KeyPair?, private val repository: ConversationRepository, private val storage: Storage, - private val messageDataProvider: MessageDataProvider, - database: MmsDatabase, + private val messageDataProvider: MessageDataProvider ) : ViewModel() { val showSendAfterApprovalText: Boolean @@ -167,14 +166,17 @@ class ConversationViewModel( * but the messages themselves won't be removed from the db. * Instead they will appear as a special type of message * that says something like "This message was deleted" + * + * @displayedMessage is the message that will be displayed in place of the deleted message. */ - fun markAsDeletedLocally(messages: Set, threadId: Long) { + fun markAsDeletedLocally(messages: Set, displayedMessage: String) { // make sure to stop audio messages, if any messages.filterIsInstance() .mapNotNull { it.slideDeck.audioSlide } .forEach(::stopMessageAudio) - repository.markAsDeletedLocally(messages, threadId) + + repository.markAsDeletedLocally(messages, displayedMessage) } /** @@ -304,7 +306,6 @@ class ConversationViewModel( @Assisted private val edKeyPair: KeyPair?, private val repository: ConversationRepository, private val storage: Storage, - private val mmsDatabase: MmsDatabase, private val messageDataProvider: MessageDataProvider, ) : ViewModelProvider.Factory { @@ -314,8 +315,7 @@ class ConversationViewModel( edKeyPair = edKeyPair, repository = repository, storage = storage, - messageDataProvider = messageDataProvider, - database = mmsDatabase + messageDataProvider = messageDataProvider ) as T } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/DeletedMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/DeletedMessageView.kt index 9c725ee048..df0665b585 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/DeletedMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/DeletedMessageView.kt @@ -21,7 +21,8 @@ class DeletedMessageView : LinearLayout { // region Updating fun bind(message: MessageRecord, @ColorInt textColor: Int) { assert(message.isDeleted) - binding.deleteTitleTextView.text = context.getString(R.string.deleted_message) + // set the text to the message's body if it is set, else use a fallback + binding.deleteTitleTextView.text = message.body.ifEmpty { context.getString(R.string.deleted_message) } binding.deleteTitleTextView.setTextColor(textColor) binding.deletedMessageViewIconImageView.imageTintList = ColorStateList.valueOf(textColor) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java index debea45484..2377ccf301 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java @@ -46,7 +46,7 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn public abstract void markUnidentified(long messageId, boolean unidentified); - public abstract void markAsDeleted(long messageId, boolean isOutgoing); + public abstract void markAsDeleted(long messageId, boolean isOutgoing, String displayedMessage); public abstract boolean deleteMessage(long messageId); public abstract boolean deleteMessages(long[] messageId, long threadId); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index b088ddd878..1a4eeefd56 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -305,11 +305,11 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa db.update(TABLE_NAME, contentValues, ID_WHERE, arrayOf(messageId.toString())) } - override fun markAsDeleted(messageId: Long, isOutgoing: Boolean) { + override fun markAsDeleted(messageId: Long, isOutgoing: Boolean, displayedMessage: String) { val database = databaseHelper.writableDatabase val contentValues = ContentValues() contentValues.put(READ, 1) - contentValues.put(BODY, "") + contentValues.put(BODY, displayedMessage) contentValues.put(HAS_MENTION, 0) database.update(TABLE_NAME, contentValues, ID_WHERE, arrayOf(messageId.toString())) val attachmentDatabase = get(context).attachmentDatabase() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index f12e041f40..3dfb9362e1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -236,11 +236,11 @@ public class SmsDatabase extends MessagingDatabase { } @Override - public void markAsDeleted(long messageId, boolean isOutgoing) { + public void markAsDeleted(long messageId, boolean isOutgoing, String displayedMessage) { SQLiteDatabase database = databaseHelper.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(READ, 1); - contentValues.put(BODY, ""); + contentValues.put(BODY, displayedMessage); contentValues.put(HAS_MENTION, 0); database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(messageId)}); diff --git a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt index a0ce018c49..6016592725 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt @@ -57,7 +57,7 @@ interface ConversationRepository { fun clearDrafts(threadId: Long) fun inviteContacts(threadId: Long, contacts: List) fun setBlocked(recipient: Recipient, blocked: Boolean) - fun markAsDeletedLocally(messages: Set, threadId: Long) + fun markAsDeletedLocally(messages: Set, displayedMessage: String) fun deleteMessages(messages: Set, threadId: Long) fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord) fun setApproved(recipient: Recipient, isApproved: Boolean) @@ -182,7 +182,7 @@ class DefaultConversationRepository @Inject constructor( * They won't be removed from the db but instead will appear as a special type * of message that says something like "This message was deleted" */ - override fun markAsDeletedLocally(messages: Set, threadId: Long) { + override fun markAsDeletedLocally(messages: Set, displayedMessage: String) { // split the messages into mms and sms val (mms, sms) = messages.partition { it.isMms } @@ -190,14 +190,20 @@ class DefaultConversationRepository @Inject constructor( messageDataProvider.markMessagesAsDeleted(mms.map { MarkAsDeletedMessage( messageId = it.id, isOutgoing = it.isOutgoing - ) }, threadId, isSms = false) + ) }, + isSms = false, + displayedMessage = displayedMessage + ) } if(sms.isNotEmpty()){ messageDataProvider.markMessagesAsDeleted(sms.map { MarkAsDeletedMessage( messageId = it.id, isOutgoing = it.isOutgoing - ) }, threadId, isSms = true) + ) }, + isSms = true, + displayedMessage = displayedMessage + ) } //todo DELETION delete attachments and links diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt index 9e7b63a18d..e8696ec282 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt @@ -28,7 +28,6 @@ class ConversationViewModelTest: BaseViewModelTest() { private val repository = mock() private val storage = mock() - private val mmsDatabase = mock() private val threadId = 123L private val edKeyPair = mock() @@ -36,7 +35,7 @@ class ConversationViewModelTest: BaseViewModelTest() { private lateinit var messageRecord: MessageRecord private val viewModel: ConversationViewModel by lazy { - ConversationViewModel(threadId, edKeyPair, repository, storage, mock(), mmsDatabase) + ConversationViewModel(threadId, edKeyPair, repository, storage, mock()) } @Before diff --git a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt index 78cdefd38d..1b6dda5e99 100644 --- a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt +++ b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt @@ -24,8 +24,8 @@ interface MessageDataProvider { fun getMessageIDs(serverIDs: List, threadID: Long): Pair, List> fun deleteMessage(messageID: Long, isSms: Boolean) fun deleteMessages(messageIDs: List, threadId: Long, isSms: Boolean) - fun updateMessageAsDeleted(timestamp: Long, author: String): Long? - fun markMessagesAsDeleted(messages: List, threadId: Long, isSms: Boolean) + fun markMessageAsDeleted(timestamp: Long, author: String, displayedMessage: String): Long? + fun markMessagesAsDeleted(messages: List, isSms: Boolean, displayedMessage: String) fun getServerHashForMessage(messageID: Long, mms: Boolean): String? fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment? fun getAttachmentStream(attachmentId: Long): SessionServiceAttachmentStream? diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index 311d8034ad..4fac5963fb 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -258,7 +258,11 @@ fun MessageReceiver.handleUnsendRequest(message: UnsendRequest): Long? { messageDataProvider.getServerHashForMessage(messageIdToDelete, mms)?.let { serverHash -> SnodeAPI.deleteMessage(author, listOf(serverHash)) } - val deletedMessageId = messageDataProvider.updateMessageAsDeleted(timestamp, author) + val deletedMessageId = messageDataProvider.markMessageAsDeleted( + timestamp = timestamp, + author = author, + displayedMessage = "[UPDATE THIS!] This message was deleted on this device" //todo DELETION update once we have strings + ) if (!messageDataProvider.isOutgoingMessage(timestamp)) { SSKEnvironment.shared.notificationManager.updateNotification(context) }