Displaying "marked as deleted" messages

Split the `BASE_DELETED_TYPE` into two types:
BASE_DELETED_OUTGOING_TYPE and BASE_DELETED_INCOMING_TYPE
so we can differentiate them visually.
pull/1647/head
ThomasSession 10 months ago
parent 6e315a18f4
commit 7a7d04b6d7

@ -6,6 +6,7 @@ import com.google.protobuf.ByteString
import org.greenrobot.eventbus.EventBus
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.MarkAsDeletedMessage
import org.session.libsession.messaging.messages.control.UnsendRequest
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
@ -221,7 +222,8 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
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)
messagingDatabase.markAsDeleted(message.id, message.isOutgoing)
if (message.isOutgoing) {
messagingDatabase.deleteMessage(message.id)
}
@ -230,7 +232,7 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
}
override fun markMessagesAsDeleted(
messageIDs: List<Long>,
messages: List<MarkAsDeletedMessage>,
threadId: Long,
isSms: Boolean
) {
@ -240,8 +242,8 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
//todo DELETION can this be batched?
//todo DELETION we need to have different types of "marked as deleted": incoming and outgoing
//todo DELETION we need to have customisable text for "marked as deleted" message
messageIDs.forEach { messageID ->
messagingDatabase.markAsDeleted(messageID)
messages.forEach { message ->
messagingDatabase.markAsDeleted(message.messageId, message.isOutgoing)
}
}

@ -262,13 +262,12 @@ class VisibleMessageView : LinearLayout {
// Get details regarding how we should display the message (it's delivery icon, icon tint colour, and
// the resource string for what text to display (R.string.delivery_status_sent etc.).
val (iconID, iconColor, textId) = getMessageStatusInfo(message)
// If we get any nulls then a message isn't one with a state that we care about (i.e., control messages
// If we get a null messageStatus then the message isn't one with a state that we care about (i.e., control messages
// etc.) - so bail. See: `DisplayRecord.is<WHATEVER>` for the full suite of message state methods.
// Also: We set all delivery status elements visibility to false just to make sure we don't display any
// stale data.
if (textId == null) return
val messageStatus = getMessageStatusInfo(message) ?: return
binding.messageInnerLayout.modifyLayoutParams<FrameLayout.LayoutParams> {
gravity = if (message.isOutgoing) Gravity.END else Gravity.START
@ -277,16 +276,17 @@ class VisibleMessageView : LinearLayout {
horizontalBias = if (message.isOutgoing) 1f else 0f
}
// If the message is incoming AND it is not scheduled to disappear then don't show any status or timer details
// If the message is incoming AND it is not scheduled to disappear
// OR it is a deleted message then don't show any status or timer details
val scheduledToDisappear = message.expiresIn > 0
if (message.isIncoming && !scheduledToDisappear) return
if (message.isDeleted || message.isIncoming && !scheduledToDisappear) return
// Set text & icons as appropriate for the message state. Note: Possible message states we care
// about are: isFailed, isSyncFailed, isPending, isSyncing, isResyncing, isRead, and isSent.
textId.let(binding.messageStatusTextView::setText)
iconColor?.let(binding.messageStatusTextView::setTextColor)
iconID?.let { ContextCompat.getDrawable(context, it) }
?.run { iconColor?.let { mutate().apply { setTint(it) } } ?: this }
messageStatus.messageText?.let(binding.messageStatusTextView::setText)
messageStatus.iconTint?.let(binding.messageStatusTextView::setTextColor)
messageStatus.iconId?.let { ContextCompat.getDrawable(context, it) }
?.run { messageStatus.iconTint?.let { mutate().apply { setTint(it) } } ?: this }
?.let(binding.messageStatusImageView::setImageDrawable)
// Potential options at this point are that the message is:
@ -363,7 +363,7 @@ class VisibleMessageView : LinearLayout {
@ColorInt val iconTint: Int?,
@StringRes val messageText: Int?)
private fun getMessageStatusInfo(message: MessageRecord): MessageStatusInfo = when {
private fun getMessageStatusInfo(message: MessageRecord): MessageStatusInfo? = when {
message.isFailed ->
MessageStatusInfo(R.drawable.ic_delivery_status_failed,
getThemedColor(context, R.attr.danger),
@ -399,10 +399,15 @@ class VisibleMessageView : LinearLayout {
context.getColorFromAttr(R.attr.message_status_color),
R.string.delivery_status_sent
)
// deleted messages do not have a status but we care about styling them so they need to return something
message.isDeleted ->
MessageStatusInfo(null, null, null)
else -> {
// The message isn't one we care about for message statuses we display to the user (i.e.,
// control messages etc. - see the `DisplayRecord.is<WHATEVER>` suite of methods for options).
MessageStatusInfo(null, null, null)
null
}
}

@ -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);
public abstract void markAsDeleted(long messageId, boolean isOutgoing);
public abstract boolean deleteMessage(long messageId);
public abstract boolean deleteMessages(long[] messageId, long threadId);

@ -290,7 +290,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
db.update(TABLE_NAME, contentValues, ID_WHERE, arrayOf(messageId.toString()))
}
override fun markAsDeleted(messageId: Long) {
override fun markAsDeleted(messageId: Long, isOutgoing: Boolean) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues()
contentValues.put(READ, 1)
@ -301,7 +301,10 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
queue(Runnable { attachmentDatabase.deleteAttachmentsForMessage(messageId) })
val threadId = getThreadIdForMessage(messageId)
markAs(messageId, MmsSmsColumns.Types.BASE_DELETED_TYPE, threadId)
val deletedType = if (isOutgoing) { MmsSmsColumns.Types.BASE_DELETED_OUTGOING_TYPE} else {
MmsSmsColumns.Types.BASE_DELETED_INCOMING_TYPE
}
markAs(messageId, deletedType, threadId)
}
override fun markExpireStarted(messageId: Long, startedTimestamp: Long) {

@ -50,10 +50,11 @@ public interface MmsSmsColumns {
protected static final long BASE_PENDING_SECURE_SMS_FALLBACK = 25;
protected static final long BASE_PENDING_INSECURE_SMS_FALLBACK = 26;
public static final long BASE_DRAFT_TYPE = 27;
protected static final long BASE_DELETED_TYPE = 28;
protected static final long BASE_DELETED_OUTGOING_TYPE = 28;
protected static final long BASE_SYNCING_TYPE = 29;
protected static final long BASE_RESYNCING_TYPE = 30;
protected static final long BASE_SYNC_FAILED_TYPE = 31;
protected static final long BASE_DELETED_INCOMING_TYPE = 32;
protected static final long[] OUTGOING_MESSAGE_TYPES = {BASE_OUTBOX_TYPE, BASE_SENT_TYPE,
BASE_SYNCING_TYPE, BASE_RESYNCING_TYPE,
@ -61,6 +62,7 @@ public interface MmsSmsColumns {
BASE_SENDING_TYPE, BASE_SENT_FAILED_TYPE,
BASE_PENDING_SECURE_SMS_FALLBACK,
BASE_PENDING_INSECURE_SMS_FALLBACK,
BASE_DELETED_OUTGOING_TYPE,
OUTGOING_CALL_TYPE};
@ -182,7 +184,10 @@ public interface MmsSmsColumns {
return (type & BASE_TYPE_MASK) == BASE_INBOX_TYPE;
}
public static boolean isDeletedMessage(long type) { return (type & BASE_TYPE_MASK) == BASE_DELETED_TYPE; }
public static boolean isDeletedMessage(long type) {
return (type & BASE_TYPE_MASK) == BASE_DELETED_OUTGOING_TYPE ||
(type & BASE_TYPE_MASK) == BASE_DELETED_INCOMING_TYPE;
}
public static boolean isJoinedType(long type) {
return (type & BASE_TYPE_MASK) == JOINED_TYPE;

@ -236,14 +236,17 @@ public class SmsDatabase extends MessagingDatabase {
}
@Override
public void markAsDeleted(long messageId) {
public void markAsDeleted(long messageId, boolean isOutgoing) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(READ, 1);
contentValues.put(BODY, "");
contentValues.put(HAS_MENTION, 0);
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(messageId)});
updateTypeBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_DELETED_TYPE);
updateTypeBitmask(messageId, Types.BASE_TYPE_MASK,
isOutgoing? MmsSmsColumns.Types.BASE_DELETED_OUTGOING_TYPE : MmsSmsColumns.Types.BASE_DELETED_INCOMING_TYPE
);
}
@Override

@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.messages.MarkAsDeletedMessage
import org.session.libsession.messaging.messages.control.MessageRequestResponse
import org.session.libsession.messaging.messages.control.UnsendRequest
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
@ -186,11 +187,17 @@ class DefaultConversationRepository @Inject constructor(
val (mms, sms) = messages.partition { it.isMms }
if(mms.isNotEmpty()){
messageDataProvider.markMessagesAsDeleted(mms.map { it.id }, threadId, isSms = false)
messageDataProvider.markMessagesAsDeleted(mms.map { MarkAsDeletedMessage(
messageId = it.id,
isOutgoing = it.isOutgoing
) }, threadId, isSms = false)
}
if(sms.isNotEmpty()){
messageDataProvider.markMessagesAsDeleted(sms.map { it.id }, threadId, isSms = true)
messageDataProvider.markMessagesAsDeleted(sms.map { MarkAsDeletedMessage(
messageId = it.id,
isOutgoing = it.isOutgoing
) }, threadId, isSms = true)
}
//todo DELETION delete attachments and links

@ -2,12 +2,11 @@
<org.thoughtcrime.securesms.conversation.v2.messages.DeletedMessageView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:padding="@dimen/small_spacing"
android:gravity="center">
android:padding="@dimen/small_spacing">
<ImageView
android:id="@+id/deletedMessageViewIconImageView"

@ -5,6 +5,7 @@
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mainContainerConstraint"
android:background="@color/red_400"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.thoughtcrime.securesms.util.MessageBubbleView
@ -24,6 +25,7 @@
android:id="@+id/deletedMessageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_bias="0"
/>
<include layout="@layout/view_untrusted_attachment"

@ -1,5 +1,6 @@
package org.session.libsession.database
import org.session.libsession.messaging.messages.MarkAsDeletedMessage
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
@ -24,7 +25,7 @@ interface MessageDataProvider {
fun deleteMessage(messageID: Long, isSms: Boolean)
fun deleteMessages(messageIDs: List<Long>, threadId: Long, isSms: Boolean)
fun updateMessageAsDeleted(timestamp: Long, author: String): Long?
fun markMessagesAsDeleted(messageIDs: List<Long>, threadId: Long, isSms: Boolean)
fun markMessagesAsDeleted(messages: List<MarkAsDeletedMessage>, threadId: Long, isSms: Boolean)
fun getServerHashForMessage(messageID: Long, mms: Boolean): String?
fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment?
fun getAttachmentStream(attachmentId: Long): SessionServiceAttachmentStream?

@ -0,0 +1,6 @@
package org.session.libsession.messaging.messages
data class MarkAsDeletedMessage(
val messageId: Long,
val isOutgoing: Boolean
)
Loading…
Cancel
Save