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 69232d79d1..9182c4d655 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -1678,17 +1678,39 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .run() } - fun getIncomingMeaningfulMessageCountSince(threadId: Long, afterTime: Long): Int { - val meaningfulMessagesQuery = buildMeaningfulMessagesQuery(threadId) - val where = "${meaningfulMessagesQuery.where} AND $DATE_RECEIVED >= ? AND NOT ($outgoingTypeClause)" - val whereArgs = appendArg(meaningfulMessagesQuery.whereArgs, afterTime.toString()) + /** + * Returns the receipt status of the most recent meaningful message in the thread if it matches the provided message ID. + * If the ID doesn't match or otherwise can't be found, it will return null. + * + * This is a very specific method for use with [ThreadTable.updateReceiptStatus] to improve the perfomance of + * processing receipts. + */ + fun getReceiptStatusIfItsTheMostRecentMeaningfulMessage(messageId: Long, threadId: Long): MessageReceiptStatus? { + val query = buildMeaningfulMessagesQuery(threadId) return readableDatabase - .select("COUNT(*)") + .select(ID, DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, VIEWED_RECEIPT_COUNT, TYPE) .from(TABLE_NAME) - .where(where, whereArgs) + .where(query.where, query.whereArgs) + .orderBy("$DATE_RECEIVED DESC") + .limit(1) .run() - .readToSingleInt() + .use { cursor -> + if (cursor.moveToFirst()) { + if (cursor.requireLong(ID) != messageId) { + return null + } + + return MessageReceiptStatus( + deliveryCount = cursor.requireInt(DELIVERY_RECEIPT_COUNT), + readCount = cursor.requireInt(READ_RECEIPT_COUNT), + viewedCount = cursor.requireInt(VIEWED_RECEIPT_COUNT), + type = cursor.requireLong(TYPE) + ) + } else { + null + } + } } private fun buildMeaningfulMessagesQuery(threadId: Long): SqlUtil.Query { @@ -4129,7 +4151,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat messageUpdates = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier) for (messageUpdate in messageUpdates) { - threads.update(messageUpdate.threadId, false) + threads.updateReceiptStatus(messageUpdate.messageId.id, messageUpdate.threadId) } } @@ -4161,7 +4183,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat for (update in messageUpdates) { if (update.shouldUpdateSnippet) { - threads.updateSilently(update.threadId, false) + threads.updateReceiptStatus(update.messageId.id, update.threadId) } } } @@ -4722,6 +4744,17 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat VIEWED(VIEWED_RECEIPT_COUNT, GroupReceiptTable.STATUS_VIEWED) } + data class MessageReceiptStatus( + val readCount: Int, + val deliveryCount: Int, + val viewedCount: Int, + val type: Long + ) + + enum class MessageStatus { + PENDING, SENT, DELIVERED, READ, VIEWED, FAILED + } + data class SyncMessageId( val recipientId: RecipientId, val timetamp: Long diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt index 1244318e83..9c0ea337fe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt @@ -1402,6 +1402,35 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa ) } + /** + * Updates the thread with the receipt status of the message provided, but only if that message is the most recent meaningful message. + * The idea here is that if it _is_ the most meaningful message, we can set the new status. If it's not, there's no need to update + * the thread at all. + */ + fun updateReceiptStatus(messageId: Long, threadId: Long) { + val status = messages.getReceiptStatusIfItsTheMostRecentMeaningfulMessage(messageId, threadId) + + if (status != null) { + Log.d(TAG, "Updating receipt status for thread $threadId") + writableDatabase + .update(TABLE_NAME) + .values( + DELIVERY_RECEIPT_COUNT to status.deliveryCount, + READ_RECEIPT_COUNT to status.readCount, + STATUS to when { + MessageTypes.isFailedMessageType(status.type) -> MessageTable.Status.STATUS_FAILED + MessageTypes.isSentType(status.type) -> MessageTable.Status.STATUS_COMPLETE + MessageTypes.isPendingMessageType(status.type) -> MessageTable.Status.STATUS_PENDING + else -> MessageTable.Status.STATUS_NONE + } + ) + .where("$ID = ?", threadId) + .run() + } else { + Log.d(TAG, "Receipt was for an old message, not updating thread.") + } + } + private fun update(threadId: Long, unarchive: Boolean, allowDeletion: Boolean, notifyListeners: Boolean): Boolean { if (threadId == -1L) { Log.d(TAG, "Skipping update for threadId -1")