diff --git a/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt b/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt index 9fb49d98ef..2a0b90f4ce 100644 --- a/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt +++ b/app/src/debug/java/org/thoughtcrime/securesms/components/settings/app/internal/conversation/test/ConversationElementGenerator.kt @@ -117,7 +117,8 @@ class ConversationElementGenerator { -1, null, null, - 0 + 0, + false ) val conversationMessage = ConversationMessageFactory.createWithUnresolvedData( diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations.kt index 9e596066a4..1164aad3d4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationItemDecorations.kt @@ -125,8 +125,8 @@ class ConversationItemDecorations(hasWallpaper: Boolean = false, private val sch val state: UnreadState = unreadState if (state is UnreadState.InitialUnreadState) { - val firstUnread = items[(state.unreadCount - 1).coerceIn(items.indices)] - val timestamp = (firstUnread as? ConversationMessageElement)?.timestamp() + val firstUnread: ConversationMessageElement? = findFirstUnreadStartingAt(items, (state.unreadCount - 1).coerceIn(items.indices)) + val timestamp = firstUnread?.timestamp() if (timestamp != null) { unreadState = UnreadState.CompleteUnreadState(unreadCount = state.unreadCount, firstUnreadTimestamp = timestamp) } @@ -149,6 +149,17 @@ class ConversationItemDecorations(hasWallpaper: Boolean = false, private val sch } } + private fun findFirstUnreadStartingAt(items: List, startingIndex: Int): ConversationMessageElement? { + val endingIndex = (startingIndex + 20).coerceAtMost(items.lastIndex) + for (index in startingIndex..endingIndex) { + val item = items[index] as? ConversationMessageElement + if ((item?.conversationMessage?.messageRecord as? MmsMessageRecord)?.isRead == false) { + return item + } + } + return items[startingIndex] as? ConversationMessageElement + } + private fun isFirstUnread(bindingAdapterPosition: Int): Boolean { val state = unreadState diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt index d45d7bd17f..9b633e9cdb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -4995,6 +4995,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val latestRevisionId: MessageId? = cursor.requireLong(LATEST_REVISION_ID).let { if (it == 0L) null else MessageId(it) } val originalMessageId: MessageId? = cursor.requireLong(ORIGINAL_MESSAGE_ID).let { if (it == 0L) null else MessageId(it) } val editCount = cursor.requireInt(REVISION_NUMBER) + val isRead = cursor.requireBoolean(READ) if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { hasReadReceipt = false @@ -5081,7 +5082,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat scheduledDate, latestRevisionId, originalMessageId, - editCount + editCount, + isRead ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java index e4f4988d7f..5091055e20 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java @@ -70,6 +70,7 @@ public class MmsMessageRecord extends MessageRecord { private final CallTable.Call call; private final long scheduledDate; private final MessageId latestRevisionId; + private final boolean isRead; public MmsMessageRecord(long id, Recipient fromRecipient, @@ -109,26 +110,28 @@ public class MmsMessageRecord extends MessageRecord { long scheduledDate, @Nullable MessageId latestRevisionId, @Nullable MessageId originalMessageId, - int revisionNumber) + int revisionNumber, + boolean isRead) { super(id, body, fromRecipient, fromDeviceId, toRecipient, dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, hasDeliveryReceipt, mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, hasReadReceipt, unidentified, reactions, remoteDelete, notifiedTimestamp, viewed, receiptTimestamp, originalMessageId, revisionNumber); - this.slideDeck = slideDeck; - this.quote = quote; - this.viewOnce = viewOnce; - this.storyType = storyType; - this.parentStoryId = parentStoryId; - this.giftBadge = giftBadge; - this.mentionsSelf = mentionsSelf; - this.messageRanges = messageRanges; - this.payment = payment; - this.call = call; - this.scheduledDate = scheduledDate; - this.latestRevisionId = latestRevisionId; - + this.slideDeck = slideDeck; + this.quote = quote; + this.viewOnce = viewOnce; + this.storyType = storyType; + this.parentStoryId = parentStoryId; + this.giftBadge = giftBadge; + this.mentionsSelf = mentionsSelf; + this.messageRanges = messageRanges; + this.payment = payment; + this.call = call; + this.scheduledDate = scheduledDate; + this.latestRevisionId = latestRevisionId; + this.isRead = isRead; + this.contacts.addAll(contacts); this.linkPreviews.addAll(linkPreviews); } @@ -197,6 +200,10 @@ public class MmsMessageRecord extends MessageRecord { return false; } + public boolean isRead() { + return isRead; + } + @Override @WorkerThread public SpannableString getDisplayBody(@NonNull Context context) { @@ -280,7 +287,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber()); + getOriginalMessageId(), getRevisionNumber(), isRead()); } public @NonNull MmsMessageRecord withoutQuote() { @@ -288,7 +295,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber()); + getOriginalMessageId(), getRevisionNumber(), isRead()); } public @NonNull MmsMessageRecord withAttachments(@NonNull List attachments) { @@ -310,7 +317,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber()); + getOriginalMessageId(), getRevisionNumber(), isRead()); } public @NonNull MmsMessageRecord withPayment(@NonNull Payment payment) { @@ -318,7 +325,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber()); + getOriginalMessageId(), getRevisionNumber(), isRead()); } @@ -327,7 +334,7 @@ public class MmsMessageRecord extends MessageRecord { getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate(), getLatestRevisionId(), - getOriginalMessageId(), getRevisionNumber()); + getOriginalMessageId(), getRevisionNumber(), isRead()); } private static @NonNull List updateContacts(@NonNull List contacts, @NonNull Map attachmentIdMap) { diff --git a/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt b/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt index 177c78be13..5134ffbebc 100644 --- a/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt +++ b/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt @@ -183,7 +183,8 @@ object FakeMessageRecords { -1, null, null, - 0 + 0, + false ) } }