mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Store receipt fields as booleans instead of counts.
This commit is contained in:
@@ -416,7 +416,7 @@ public class ConversationItemFooter extends ConstraintLayout {
|
||||
deliveryStatusView.setNone();
|
||||
} else if (messageRecord.isPending()) {
|
||||
deliveryStatusView.setPending();
|
||||
} else if (messageRecord.isRemoteRead()) {
|
||||
} else if (messageRecord.hasReadReceipt()) {
|
||||
deliveryStatusView.setRead();
|
||||
} else if (messageRecord.isDelivered()) {
|
||||
deliveryStatusView.setDelivered();
|
||||
@@ -433,7 +433,7 @@ public class ConversationItemFooter extends ConstraintLayout {
|
||||
if (mmsMessageRecord.getSlideDeck().getAudioSlide() != null) {
|
||||
showAudioDurationViews();
|
||||
|
||||
if (messageRecord.getViewedReceiptCount() > 0 || (messageRecord.isOutgoing() && Objects.equals(messageRecord.getToRecipient(), Recipient.self()))) {
|
||||
if (messageRecord.isViewed() || (messageRecord.isOutgoing() && Objects.equals(messageRecord.getToRecipient(), Recipient.self()))) {
|
||||
revealDot.setProgress(1f);
|
||||
} else {
|
||||
revealDot.setProgress(0f);
|
||||
|
||||
@@ -2243,7 +2243,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||
|
||||
@Override
|
||||
public @Nullable Projection getOpenableGiftProjection(boolean isAnimating) {
|
||||
if (!isGiftMessage(messageRecord) || messageRecord.isRemoteDelete() || (messageRecord.getViewedReceiptCount() > 0 && !isAnimating)) {
|
||||
if (!isGiftMessage(messageRecord) || messageRecord.isRemoteDelete() || (messageRecord.isViewed() && !isAnimating)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -700,7 +700,7 @@ open class V2ConversationItemTextOnlyViewHolder<Model : MappingModel<Model>>(
|
||||
|
||||
when {
|
||||
record.isPending -> deliveryStatus.setPending()
|
||||
record.isRemoteRead -> deliveryStatus.setRead()
|
||||
record.hasReadReceipt() -> deliveryStatus.setRead()
|
||||
record.isDelivered -> deliveryStatus.setDelivered()
|
||||
else -> deliveryStatus.setSent()
|
||||
}
|
||||
|
||||
@@ -516,7 +516,7 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
|
||||
} else {
|
||||
if (thread.isPending()) {
|
||||
deliveryStatusIndicator.setPending();
|
||||
} else if (thread.isRemoteRead()) {
|
||||
} else if (thread.hasReadReceipt()) {
|
||||
deliveryStatusIndicator.setRead();
|
||||
} else if (thread.isDelivered()) {
|
||||
deliveryStatusIndicator.setDelivered();
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.signal.core.util.SqlUtil.buildCustomCollectionQuery
|
||||
import org.signal.core.util.SqlUtil.buildSingleCollectionQuery
|
||||
import org.signal.core.util.SqlUtil.buildTrueUpdateQuery
|
||||
import org.signal.core.util.SqlUtil.getNextAutoIncrementId
|
||||
import org.signal.core.util.Stopwatch
|
||||
import org.signal.core.util.count
|
||||
import org.signal.core.util.delete
|
||||
import org.signal.core.util.exists
|
||||
@@ -164,9 +165,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
const val FROM_RECIPIENT_ID = "from_recipient_id"
|
||||
const val FROM_DEVICE_ID = "from_device_id"
|
||||
const val TO_RECIPIENT_ID = "to_recipient_id"
|
||||
const val DELIVERY_RECEIPT_COUNT = "delivery_receipt_count"
|
||||
const val READ_RECEIPT_COUNT = "read_receipt_count"
|
||||
const val VIEWED_RECEIPT_COUNT = "viewed_receipt_count"
|
||||
const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt"
|
||||
const val HAS_READ_RECEIPT = "has_read_receipt"
|
||||
const val VIEWED_COLUMN = "viewed"
|
||||
const val MISMATCHED_IDENTITIES = "mismatched_identities"
|
||||
const val SMS_SUBSCRIPTION_ID = "subscription_id"
|
||||
const val EXPIRES_IN = "expires_in"
|
||||
@@ -227,9 +228,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
$MMS_TRANSACTION_ID TEXT,
|
||||
$SMS_SUBSCRIPTION_ID INTEGER DEFAULT -1,
|
||||
$RECEIPT_TIMESTAMP INTEGER DEFAULT -1,
|
||||
$DELIVERY_RECEIPT_COUNT INTEGER DEFAULT 0,
|
||||
$READ_RECEIPT_COUNT INTEGER DEFAULT 0,
|
||||
$VIEWED_RECEIPT_COUNT INTEGER DEFAULT 0,
|
||||
$HAS_DELIVERY_RECEIPT INTEGER DEFAULT 0,
|
||||
$HAS_READ_RECEIPT INTEGER DEFAULT 0,
|
||||
$VIEWED_COLUMN INTEGER DEFAULT 0,
|
||||
$MISMATCHED_IDENTITIES TEXT DEFAULT NULL,
|
||||
$NETWORK_FAILURES TEXT DEFAULT NULL,
|
||||
$EXPIRES_IN INTEGER DEFAULT 0,
|
||||
@@ -307,8 +308,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
FROM_RECIPIENT_ID,
|
||||
FROM_DEVICE_ID,
|
||||
TO_RECIPIENT_ID,
|
||||
DELIVERY_RECEIPT_COUNT,
|
||||
READ_RECEIPT_COUNT,
|
||||
HAS_DELIVERY_RECEIPT,
|
||||
HAS_READ_RECEIPT,
|
||||
MISMATCHED_IDENTITIES,
|
||||
NETWORK_FAILURES,
|
||||
SMS_SUBSCRIPTION_ID,
|
||||
@@ -330,7 +331,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
REMOTE_DELETED,
|
||||
MENTIONS_SELF,
|
||||
NOTIFIED_TIMESTAMP,
|
||||
VIEWED_RECEIPT_COUNT,
|
||||
VIEWED_COLUMN,
|
||||
RECEIPT_TIMESTAMP,
|
||||
MESSAGE_RANGES,
|
||||
STORY_TYPE,
|
||||
@@ -665,7 +666,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
return readableDatabase
|
||||
.select(ID, FROM_RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE)
|
||||
.from(TABLE_NAME)
|
||||
.where("$THREAD_ID = ? AND $VIEWED_RECEIPT_COUNT > 0 AND $TYPE & ${MessageTypes.BASE_INBOX_TYPE} = ${MessageTypes.BASE_INBOX_TYPE}", threadId)
|
||||
.where("$THREAD_ID = ? AND $VIEWED_COLUMN > 0 AND $TYPE & ${MessageTypes.BASE_INBOX_TYPE} = ${MessageTypes.BASE_INBOX_TYPE}", threadId)
|
||||
.run()
|
||||
.readToList { it.toMarkedMessageInfo(outgoing = false) }
|
||||
}
|
||||
@@ -687,7 +688,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val results: List<MarkedMessageInfo> = readableDatabase
|
||||
.select(ID, FROM_RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE)
|
||||
.from(TABLE_NAME)
|
||||
.where("$ID IN (${Util.join(messageIds, ",")}) AND $VIEWED_RECEIPT_COUNT = 0")
|
||||
.where("$ID IN (${Util.join(messageIds, ",")}) AND $VIEWED_COLUMN = 0")
|
||||
.run()
|
||||
.readToList { cursor ->
|
||||
val type = cursor.requireLong(TYPE)
|
||||
@@ -707,7 +708,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
VIEWED_RECEIPT_COUNT to 1,
|
||||
VIEWED_COLUMN to 1,
|
||||
RECEIPT_TIMESTAMP to currentTime
|
||||
)
|
||||
.where(query.where, query.whereArgs)
|
||||
@@ -734,7 +735,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val results: List<MarkedMessageInfo> = readableDatabase
|
||||
.select(ID, TO_RECIPIENT_ID, DATE_SENT, THREAD_ID, STORY_TYPE)
|
||||
.from(TABLE_NAME)
|
||||
.where("""$ID IN (${Util.join(messageIds, ",")}) AND ($outgoingTypeClause) AND ($TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} = ${MessageTypes.SPECIAL_TYPE_GIFT_BADGE}) AND $VIEWED_RECEIPT_COUNT = 0""")
|
||||
.where("""$ID IN (${Util.join(messageIds, ",")}) AND ($outgoingTypeClause) AND ($TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} = ${MessageTypes.SPECIAL_TYPE_GIFT_BADGE}) AND $VIEWED_COLUMN = 0""")
|
||||
.run()
|
||||
.readToList { it.toMarkedMessageInfo(outgoing = true) }
|
||||
|
||||
@@ -745,7 +746,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
VIEWED_RECEIPT_COUNT to 1,
|
||||
VIEWED_COLUMN to 1,
|
||||
RECEIPT_TIMESTAMP to currentTime
|
||||
)
|
||||
.where(query.where, query.whereArgs)
|
||||
@@ -1259,7 +1260,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
|
||||
fun getUnreadStories(recipientId: RecipientId, limit: Int): Reader {
|
||||
val threadId = threads.getThreadIdIfExistsFor(recipientId)
|
||||
val query = "$IS_STORY_CLAUSE AND NOT ($outgoingTypeClause) AND $THREAD_ID = ? AND $VIEWED_RECEIPT_COUNT = ?"
|
||||
val query = "$IS_STORY_CLAUSE AND NOT ($outgoingTypeClause) AND $THREAD_ID = ? AND $VIEWED_COLUMN = ?"
|
||||
val args = buildArgs(threadId, 0)
|
||||
return MmsReader(rawQueryWithAttachments(query, args, false, limit.toLong()))
|
||||
}
|
||||
@@ -1312,7 +1313,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
writableDatabase.withinTransaction { db ->
|
||||
db.select(FROM_RECIPIENT_ID)
|
||||
.from(TABLE_NAME)
|
||||
.where("$IS_STORY_CLAUSE AND $DATE_SENT IN ($timestamps) AND NOT ($outgoingTypeClause) AND $VIEWED_RECEIPT_COUNT > 0")
|
||||
.where("$IS_STORY_CLAUSE AND $DATE_SENT IN ($timestamps) AND NOT ($outgoingTypeClause) AND $VIEWED_COLUMN > 0")
|
||||
.run()
|
||||
.readToList { cursor -> RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) }
|
||||
.forEach { id -> recipients.updateLastStoryViewTimestamp(id) }
|
||||
@@ -1332,7 +1333,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
|
||||
val hasUnviewedStories = readableDatabase
|
||||
.exists(TABLE_NAME)
|
||||
.where("$IS_STORY_CLAUSE AND $THREAD_ID = ? AND $VIEWED_RECEIPT_COUNT = ? AND NOT ($outgoingTypeClause)", threadId, 0)
|
||||
.where("$IS_STORY_CLAUSE AND $THREAD_ID = ? AND $VIEWED_COLUMN = ? AND NOT ($outgoingTypeClause)", threadId, 0)
|
||||
.run()
|
||||
|
||||
return if (hasUnviewedStories) {
|
||||
@@ -1369,7 +1370,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
WHERE
|
||||
$IS_STORY_CLAUSE AND
|
||||
($outgoingTypeClause) = 0 AND
|
||||
$VIEWED_RECEIPT_COUNT = 0 AND
|
||||
$VIEWED_COLUMN = 0 AND
|
||||
$TABLE_NAME.$READ = 0
|
||||
"""
|
||||
|
||||
@@ -1390,10 +1391,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
$TABLE_NAME.$ID AS mms_id,
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID},
|
||||
($outgoingTypeClause) AS is_outgoing,
|
||||
$VIEWED_RECEIPT_COUNT,
|
||||
$VIEWED_COLUMN,
|
||||
$TABLE_NAME.$DATE_SENT,
|
||||
$RECEIPT_TIMESTAMP,
|
||||
($outgoingTypeClause) = 0 AND $VIEWED_RECEIPT_COUNT = 0 AS is_unread
|
||||
($outgoingTypeClause) = 0 AND $VIEWED_COLUMN = 0 AS is_unread
|
||||
FROM $TABLE_NAME
|
||||
JOIN ${ThreadTable.TABLE_NAME} ON $TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID}
|
||||
WHERE
|
||||
@@ -1403,8 +1404,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
ORDER BY
|
||||
is_unread DESC,
|
||||
CASE
|
||||
WHEN is_outgoing = 0 AND $VIEWED_RECEIPT_COUNT = 0 THEN $TABLE_NAME.$DATE_SENT
|
||||
WHEN is_outgoing = 0 AND viewed_receipt_count > 0 THEN $RECEIPT_TIMESTAMP
|
||||
WHEN is_outgoing = 0 AND $VIEWED_COLUMN = 0 THEN $TABLE_NAME.$DATE_SENT
|
||||
WHEN is_outgoing = 0 AND $VIEWED_COLUMN > 0 THEN $RECEIPT_TIMESTAMP
|
||||
WHEN is_outgoing = 1 THEN $TABLE_NAME.$DATE_SENT
|
||||
END DESC
|
||||
"""
|
||||
@@ -1686,7 +1687,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val query = buildMeaningfulMessagesQuery(threadId)
|
||||
|
||||
return readableDatabase
|
||||
.select(ID, DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, VIEWED_RECEIPT_COUNT, TYPE)
|
||||
.select(ID, HAS_DELIVERY_RECEIPT, HAS_READ_RECEIPT, TYPE)
|
||||
.from(TABLE_NAME)
|
||||
.where(query.where, query.whereArgs)
|
||||
.orderBy("$DATE_RECEIVED DESC")
|
||||
@@ -1699,9 +1700,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
}
|
||||
|
||||
return MessageReceiptStatus(
|
||||
deliveryCount = cursor.requireInt(DELIVERY_RECEIPT_COUNT),
|
||||
readCount = cursor.requireInt(READ_RECEIPT_COUNT),
|
||||
viewedCount = cursor.requireInt(VIEWED_RECEIPT_COUNT),
|
||||
hasDeliveryReceipt = cursor.requireBoolean(HAS_DELIVERY_RECEIPT),
|
||||
hasReadReceipt = cursor.requireBoolean(HAS_READ_RECEIPT),
|
||||
type = cursor.requireLong(TYPE)
|
||||
)
|
||||
} else {
|
||||
@@ -2817,7 +2817,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
contentValues.put(FROM_RECIPIENT_ID, Recipient.self().id.serialize())
|
||||
contentValues.put(FROM_DEVICE_ID, SignalStore.account().deviceId)
|
||||
contentValues.put(TO_RECIPIENT_ID, message.threadRecipient.id.serialize())
|
||||
contentValues.put(DELIVERY_RECEIPT_COUNT, earlyDeliveryReceipts.values.sumOf { it.count })
|
||||
contentValues.put(HAS_DELIVERY_RECEIPT, earlyDeliveryReceipts.values.sumOf { it.count })
|
||||
contentValues.put(RECEIPT_TIMESTAMP, earlyDeliveryReceipts.values.map { it.timestamp }.maxOrNull() ?: -1L)
|
||||
contentValues.put(STORY_TYPE, message.storyType.code)
|
||||
contentValues.put(PARENT_STORY_ID, if (message.parentStoryId != null) message.parentStoryId.serialize() else 0)
|
||||
@@ -2832,7 +2832,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
}
|
||||
|
||||
if (message.threadRecipient.isSelf && hasAudioAttachment(message.attachments)) {
|
||||
contentValues.put(VIEWED_RECEIPT_COUNT, 1L)
|
||||
contentValues.put(VIEWED_COLUMN, 1L)
|
||||
}
|
||||
|
||||
val quoteAttachments: MutableList<Attachment> = mutableListOf()
|
||||
@@ -4074,8 +4074,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
.run()
|
||||
}
|
||||
|
||||
fun incrementDeliveryReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Set<Long> {
|
||||
return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.DELIVERY)
|
||||
fun incrementDeliveryReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long, stopwatch: Stopwatch? = null): Set<Long> {
|
||||
return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.DELIVERY, stopwatch = stopwatch)
|
||||
}
|
||||
|
||||
fun incrementDeliveryReceiptCount(targetTimestamps: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Boolean {
|
||||
@@ -4164,13 +4164,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
*
|
||||
* @return All of the target timestamps that couldn't be found in the table.
|
||||
*/
|
||||
private fun incrementReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL): Set<Long> {
|
||||
private fun incrementReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL, stopwatch: Stopwatch? = null): Set<Long> {
|
||||
val messageUpdates: MutableSet<MessageReceiptUpdate> = HashSet()
|
||||
val missingTargetTimestamps: MutableSet<Long> = HashSet()
|
||||
|
||||
writableDatabase.withinTransaction {
|
||||
for (targetTimestamp in targetTimestamps) {
|
||||
val updates: Set<MessageReceiptUpdate> = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier)
|
||||
val updates: Set<MessageReceiptUpdate> = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier, stopwatch)
|
||||
if (updates.isNotEmpty()) {
|
||||
messageUpdates += updates
|
||||
} else {
|
||||
@@ -4180,7 +4180,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
|
||||
for (update in messageUpdates) {
|
||||
if (update.shouldUpdateSnippet) {
|
||||
threads.updateReceiptStatus(update.messageId.id, update.threadId)
|
||||
threads.updateReceiptStatus(update.messageId.id, update.threadId, stopwatch)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4198,71 +4198,94 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
notifyConversationListListeners()
|
||||
}
|
||||
|
||||
stopwatch?.split("observers")
|
||||
|
||||
return missingTargetTimestamps
|
||||
}
|
||||
|
||||
private fun incrementReceiptCountInternal(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier): Set<MessageReceiptUpdate> {
|
||||
val messageUpdates: MutableSet<MessageReceiptUpdate> = HashSet()
|
||||
|
||||
private fun incrementReceiptCountInternal(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier, stopwatch: Stopwatch? = null): Set<MessageReceiptUpdate> {
|
||||
val qualifierWhere: String = when (messageQualifier) {
|
||||
MessageQualifier.NORMAL -> " AND NOT ($IS_STORY_CLAUSE)"
|
||||
MessageQualifier.STORY -> " AND $IS_STORY_CLAUSE"
|
||||
MessageQualifier.ALL -> ""
|
||||
}
|
||||
|
||||
var found = false
|
||||
var hasStory = false
|
||||
writableDatabase.rawQuery(
|
||||
"""
|
||||
// Note: While it is true that multiple messages can have the same (sent, author) pair, this should only happen for stories, which are handled below.
|
||||
val receiptData: ReceiptData? = readableDatabase
|
||||
.select(ID, THREAD_ID, STORY_TYPE, receiptType.columnName, TO_RECIPIENT_ID)
|
||||
.from(TABLE_NAME)
|
||||
.where(
|
||||
"""
|
||||
$DATE_SENT = $targetTimestamp AND
|
||||
$FROM_RECIPIENT_ID = ? AND
|
||||
(
|
||||
$TO_RECIPIENT_ID = ? OR
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM ${RecipientTable.TABLE_NAME}
|
||||
WHERE
|
||||
${RecipientTable.TABLE_NAME}.${RecipientTable.ID} = $TO_RECIPIENT_ID AND
|
||||
${RecipientTable.TABLE_NAME}.${RecipientTable.TYPE} != ${RecipientTable.RecipientType.INDIVIDUAL.id}
|
||||
)
|
||||
)
|
||||
$qualifierWhere
|
||||
""",
|
||||
Recipient.self().id,
|
||||
receiptAuthor
|
||||
)
|
||||
.limit(1)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
ReceiptData(
|
||||
messageId = cursor.requireLong(ID),
|
||||
threadId = cursor.requireLong(THREAD_ID),
|
||||
storyType = StoryType.fromCode(cursor.requireInt(STORY_TYPE)),
|
||||
marked = cursor.requireBoolean(receiptType.columnName),
|
||||
forIndividualChat = cursor.requireLong(TO_RECIPIENT_ID) == receiptAuthor.toLong()
|
||||
)
|
||||
}
|
||||
|
||||
stopwatch?.split("receipt-query")
|
||||
|
||||
if (receiptData == null) {
|
||||
if (receiptType == ReceiptType.DELIVERY) {
|
||||
earlyDeliveryReceiptCache.increment(targetTimestamp, receiptAuthor, receiptSentTimestamp)
|
||||
}
|
||||
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
if (!receiptData.marked) {
|
||||
// We set the receipt_timestamp to the max of the two values because that single column represents the timestamp of the last receipt of any type.
|
||||
// That means we want to update it for each new receipt type, but we never want the time to go backwards.
|
||||
writableDatabase.execSQL(
|
||||
"""
|
||||
UPDATE $TABLE_NAME
|
||||
SET
|
||||
${receiptType.columnName} = ${receiptType.columnName} + 1,
|
||||
$RECEIPT_TIMESTAMP = CASE
|
||||
WHEN ${receiptType.columnName} = 0 THEN MAX($RECEIPT_TIMESTAMP, $receiptSentTimestamp)
|
||||
ELSE $RECEIPT_TIMESTAMP
|
||||
END
|
||||
${receiptType.columnName} = 1,
|
||||
$RECEIPT_TIMESTAMP = MAX($RECEIPT_TIMESTAMP, $receiptSentTimestamp)
|
||||
WHERE
|
||||
$DATE_SENT = $targetTimestamp AND
|
||||
$FROM_RECIPIENT_ID = ? AND
|
||||
(
|
||||
$TO_RECIPIENT_ID = ? OR
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM ${RecipientTable.TABLE_NAME}
|
||||
WHERE
|
||||
${RecipientTable.TABLE_NAME}.${RecipientTable.ID} = $TO_RECIPIENT_ID AND
|
||||
${RecipientTable.TABLE_NAME}.${RecipientTable.TYPE} != ${RecipientTable.RecipientType.INDIVIDUAL.id}
|
||||
)
|
||||
)
|
||||
$qualifierWhere
|
||||
RETURNING $ID, $THREAD_ID, $STORY_TYPE, ${receiptType.columnName}
|
||||
""",
|
||||
buildArgs(Recipient.self().id, receiptAuthor)
|
||||
).forEach { cursor ->
|
||||
val messageId = cursor.requireLong(ID)
|
||||
val threadId = cursor.requireLong(THREAD_ID)
|
||||
val storyType = StoryType.fromCode(cursor.requireInt(STORY_TYPE))
|
||||
val receiptCount = cursor.requireInt(receiptType.columnName)
|
||||
$ID = ${receiptData.messageId}
|
||||
"""
|
||||
)
|
||||
}
|
||||
stopwatch?.split("receipt-update")
|
||||
|
||||
groupReceipts.update(receiptAuthor, messageId, receiptType.groupStatus, receiptSentTimestamp)
|
||||
messageUpdates += MessageReceiptUpdate(threadId, MessageId(messageId), receiptType != ReceiptType.VIEWED && receiptCount == 1)
|
||||
|
||||
found = true
|
||||
hasStory = storyType != StoryType.NONE
|
||||
if (!receiptData.forIndividualChat) {
|
||||
groupReceipts.update(receiptAuthor, receiptData.messageId, receiptType.groupStatus, receiptSentTimestamp)
|
||||
}
|
||||
|
||||
if (!found && receiptType == ReceiptType.DELIVERY) {
|
||||
earlyDeliveryReceiptCache.increment(targetTimestamp, receiptAuthor, receiptSentTimestamp)
|
||||
}
|
||||
stopwatch?.split("group-receipt")
|
||||
|
||||
if (hasStory) {
|
||||
for (messageId in storySends.getStoryMessagesFor(receiptAuthor, targetTimestamp)) {
|
||||
groupReceipts.update(receiptAuthor, messageId.id, receiptType.groupStatus, receiptSentTimestamp)
|
||||
messageUpdates += MessageReceiptUpdate(-1, messageId, false)
|
||||
}
|
||||
return if (receiptData.storyType != StoryType.NONE) {
|
||||
val storyMessageIds = storySends.getStoryMessagesFor(receiptAuthor, targetTimestamp)
|
||||
storyMessageIds.forEach { messageId -> groupReceipts.update(receiptAuthor, messageId.id, receiptType.groupStatus, receiptSentTimestamp) }
|
||||
storyMessageIds.map { messageId -> MessageReceiptUpdate(-1, messageId, false) }.toSet()
|
||||
} else {
|
||||
setOf(MessageReceiptUpdate(receiptData.threadId, MessageId(receiptData.messageId), shouldUpdateSnippet = receiptType != ReceiptType.VIEWED && !receiptData.marked))
|
||||
}.also {
|
||||
stopwatch?.split("stories")
|
||||
}
|
||||
|
||||
return messageUpdates
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4736,15 +4759,22 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
}
|
||||
|
||||
protected enum class ReceiptType(val columnName: String, val groupStatus: Int) {
|
||||
READ(READ_RECEIPT_COUNT, GroupReceiptTable.STATUS_READ),
|
||||
DELIVERY(DELIVERY_RECEIPT_COUNT, GroupReceiptTable.STATUS_DELIVERED),
|
||||
VIEWED(VIEWED_RECEIPT_COUNT, GroupReceiptTable.STATUS_VIEWED)
|
||||
READ(HAS_READ_RECEIPT, GroupReceiptTable.STATUS_READ),
|
||||
DELIVERY(HAS_DELIVERY_RECEIPT, GroupReceiptTable.STATUS_DELIVERED),
|
||||
VIEWED(VIEWED_COLUMN, GroupReceiptTable.STATUS_VIEWED)
|
||||
}
|
||||
|
||||
data class ReceiptData(
|
||||
val messageId: Long,
|
||||
val threadId: Long,
|
||||
val storyType: StoryType,
|
||||
val marked: Boolean,
|
||||
val forIndividualChat: Boolean
|
||||
)
|
||||
|
||||
data class MessageReceiptStatus(
|
||||
val readCount: Int,
|
||||
val deliveryCount: Int,
|
||||
val viewedCount: Int,
|
||||
val hasReadReceipt: Boolean,
|
||||
val hasDeliveryReceipt: Boolean,
|
||||
val type: Long
|
||||
)
|
||||
|
||||
@@ -4942,8 +4972,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val fromRecipientId = cursor.requireLong(FROM_RECIPIENT_ID)
|
||||
val fromDeviceId = cursor.requireInt(FROM_DEVICE_ID)
|
||||
val toRecipientId = cursor.requireLong(TO_RECIPIENT_ID)
|
||||
val deliveryReceiptCount = cursor.requireInt(DELIVERY_RECEIPT_COUNT)
|
||||
var readReceiptCount = cursor.requireInt(READ_RECEIPT_COUNT)
|
||||
val hasDeliveryReceipt = cursor.requireBoolean(HAS_DELIVERY_RECEIPT)
|
||||
var hasReadReceipt = cursor.requireBoolean(HAS_READ_RECEIPT)
|
||||
val body = cursor.requireString(BODY)
|
||||
val mismatchDocument = cursor.requireString(MISMATCHED_IDENTITIES)
|
||||
val networkDocument = cursor.requireString(NETWORK_FAILURES)
|
||||
@@ -4955,7 +4985,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val remoteDelete = cursor.requireBoolean(REMOTE_DELETED)
|
||||
val mentionsSelf = cursor.requireBoolean(MENTIONS_SELF)
|
||||
val notifiedTimestamp = cursor.requireLong(NOTIFIED_TIMESTAMP)
|
||||
var viewedReceiptCount = cursor.requireInt(VIEWED_RECEIPT_COUNT)
|
||||
var isViewed = cursor.requireBoolean(VIEWED_COLUMN)
|
||||
val receiptTimestamp = cursor.requireLong(RECEIPT_TIMESTAMP)
|
||||
val messageRangesData = cursor.requireBlob(MESSAGE_RANGES)
|
||||
val storyType = StoryType.fromCode(cursor.requireInt(STORY_TYPE))
|
||||
@@ -4966,9 +4996,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val editCount = cursor.requireInt(REVISION_NUMBER)
|
||||
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
readReceiptCount = 0
|
||||
hasReadReceipt = false
|
||||
if (MessageTypes.isOutgoingMessageType(box) && !storyType.isStory) {
|
||||
viewedReceiptCount = 0
|
||||
isViewed = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5019,7 +5049,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
dateSent,
|
||||
dateReceived,
|
||||
dateServer,
|
||||
deliveryReceiptCount,
|
||||
hasDeliveryReceipt,
|
||||
threadId,
|
||||
body,
|
||||
slideDeck,
|
||||
@@ -5030,7 +5060,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
expiresIn,
|
||||
expireStarted,
|
||||
isViewOnce,
|
||||
readReceiptCount,
|
||||
hasReadReceipt,
|
||||
quote,
|
||||
contacts,
|
||||
previews,
|
||||
@@ -5039,7 +5069,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
remoteDelete,
|
||||
mentionsSelf,
|
||||
notifiedTimestamp,
|
||||
viewedReceiptCount,
|
||||
isViewed,
|
||||
receiptTimestamp,
|
||||
messageRanges,
|
||||
storyType,
|
||||
|
||||
@@ -92,7 +92,7 @@ public final class ThreadBodyUtil {
|
||||
private static @NonNull String getGiftSummary(@NonNull Context context, @NonNull MessageRecord messageRecord) {
|
||||
if (messageRecord.isOutgoing()) {
|
||||
return context.getString(R.string.ThreadRecord__you_donated_for_s, messageRecord.getToRecipient().getShortDisplayName(context));
|
||||
} else if (messageRecord.getViewedReceiptCount() > 0) {
|
||||
} else if (messageRecord.isViewed()) {
|
||||
return context.getString(R.string.ThreadRecord__you_redeemed_a_badge);
|
||||
} else {
|
||||
return context.getString(R.string.ThreadRecord__s_donated_for_you, messageRecord.getFromRecipient().getShortDisplayName(context));
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.json.JSONObject
|
||||
import org.jsoup.helper.StringUtil
|
||||
import org.signal.core.util.CursorUtil
|
||||
import org.signal.core.util.SqlUtil
|
||||
import org.signal.core.util.Stopwatch
|
||||
import org.signal.core.util.delete
|
||||
import org.signal.core.util.exists
|
||||
import org.signal.core.util.logging.Log
|
||||
@@ -23,6 +24,7 @@ import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.requireString
|
||||
import org.signal.core.util.select
|
||||
import org.signal.core.util.toInt
|
||||
import org.signal.core.util.update
|
||||
import org.signal.core.util.withinTransaction
|
||||
import org.signal.libsignal.zkgroup.InvalidInputException
|
||||
@@ -97,8 +99,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
const val SNIPPET_EXTRAS = "snippet_extras"
|
||||
const val ARCHIVED = "archived"
|
||||
const val STATUS = "status"
|
||||
const val DELIVERY_RECEIPT_COUNT = "delivery_receipt_count"
|
||||
const val READ_RECEIPT_COUNT = "read_receipt_count"
|
||||
const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt"
|
||||
const val HAS_READ_RECEIPT = "has_read_receipt"
|
||||
const val EXPIRES_IN = "expires_in"
|
||||
const val LAST_SEEN = "last_seen"
|
||||
const val HAS_SENT = "has_sent"
|
||||
@@ -127,8 +129,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
$UNREAD_COUNT INTEGER DEFAULT 0,
|
||||
$ARCHIVED INTEGER DEFAULT 0,
|
||||
$STATUS INTEGER DEFAULT 0,
|
||||
$DELIVERY_RECEIPT_COUNT INTEGER DEFAULT 0,
|
||||
$READ_RECEIPT_COUNT INTEGER DEFAULT 0,
|
||||
$HAS_DELIVERY_RECEIPT INTEGER DEFAULT 0,
|
||||
$HAS_READ_RECEIPT INTEGER DEFAULT 0,
|
||||
$EXPIRES_IN INTEGER DEFAULT 0,
|
||||
$LAST_SEEN INTEGER DEFAULT 0,
|
||||
$HAS_SENT INTEGER DEFAULT 0,
|
||||
@@ -164,10 +166,10 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
SNIPPET_EXTRAS,
|
||||
ARCHIVED,
|
||||
STATUS,
|
||||
DELIVERY_RECEIPT_COUNT,
|
||||
HAS_DELIVERY_RECEIPT,
|
||||
EXPIRES_IN,
|
||||
LAST_SEEN,
|
||||
READ_RECEIPT_COUNT,
|
||||
HAS_READ_RECEIPT,
|
||||
LAST_SCROLLED,
|
||||
PINNED,
|
||||
UNREAD_SELF_MENTION_COUNT
|
||||
@@ -242,8 +244,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
SNIPPET_EXTRAS to extraSerialized,
|
||||
MEANINGFUL_MESSAGES to if (meaningfulMessages) 1 else 0,
|
||||
STATUS to status,
|
||||
DELIVERY_RECEIPT_COUNT to deliveryReceiptCount,
|
||||
READ_RECEIPT_COUNT to readReceiptCount,
|
||||
HAS_DELIVERY_RECEIPT to deliveryReceiptCount,
|
||||
HAS_READ_RECEIPT to readReceiptCount,
|
||||
EXPIRES_IN to expiresIn,
|
||||
ACTIVE to 1,
|
||||
UNREAD_COUNT to unreadCount,
|
||||
@@ -1406,16 +1408,17 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
* 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) {
|
||||
fun updateReceiptStatus(messageId: Long, threadId: Long, stopwatch: Stopwatch? = null) {
|
||||
val status = messages.getReceiptStatusIfItsTheMostRecentMeaningfulMessage(messageId, threadId)
|
||||
stopwatch?.split("thread-query")
|
||||
|
||||
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,
|
||||
HAS_DELIVERY_RECEIPT to status.hasDeliveryReceipt.toInt(),
|
||||
HAS_READ_RECEIPT to status.hasReadReceipt.toInt(),
|
||||
STATUS to when {
|
||||
MessageTypes.isFailedMessageType(status.type) -> MessageTable.Status.STATUS_FAILED
|
||||
MessageTypes.isSentType(status.type) -> MessageTable.Status.STATUS_COMPLETE
|
||||
@@ -1428,6 +1431,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
} else {
|
||||
Log.d(TAG, "Receipt was for an old message, not updating thread.")
|
||||
}
|
||||
stopwatch?.split("thread-update")
|
||||
}
|
||||
|
||||
private fun update(threadId: Long, unarchive: Boolean, allowDeletion: Boolean, notifyListeners: Boolean): Boolean {
|
||||
@@ -1506,11 +1510,11 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
extra = getExtrasFor(record, threadBody),
|
||||
date = record.timestamp,
|
||||
status = record.deliveryStatus,
|
||||
deliveryReceiptCount = record.deliveryReceiptCount,
|
||||
deliveryReceiptCount = record.hasDeliveryReceipt().toInt(),
|
||||
type = record.type,
|
||||
unarchive = unarchive,
|
||||
expiresIn = record.expiresIn,
|
||||
readReceiptCount = record.readReceiptCount,
|
||||
readReceiptCount = record.hasReadReceipt().toInt(),
|
||||
unreadCount = unreadCount,
|
||||
unreadMentionCount = unreadMentionCount
|
||||
)
|
||||
@@ -1675,8 +1679,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
UNREAD_COUNT to 0,
|
||||
ARCHIVED to 0,
|
||||
STATUS to 0,
|
||||
DELIVERY_RECEIPT_COUNT to 0,
|
||||
READ_RECEIPT_COUNT to 0,
|
||||
HAS_DELIVERY_RECEIPT to 0,
|
||||
HAS_READ_RECEIPT to 0,
|
||||
EXPIRES_IN to 0,
|
||||
LAST_SEEN to 0,
|
||||
HAS_SENT to 0,
|
||||
@@ -1890,7 +1894,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
Recipient(recipientId, details, true)
|
||||
}
|
||||
|
||||
val readReceiptCount = if (TextSecurePreferences.isReadReceiptsEnabled(context)) cursor.requireInt(READ_RECEIPT_COUNT) else 0
|
||||
val hasReadReceipt = TextSecurePreferences.isReadReceiptsEnabled(context) && cursor.requireBoolean(HAS_READ_RECEIPT)
|
||||
val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS))
|
||||
val extra: Extra? = if (extraString != null) {
|
||||
try {
|
||||
@@ -1924,8 +1928,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
.setDate(cursor.requireLong(DATE))
|
||||
.setArchived(cursor.requireBoolean(ARCHIVED))
|
||||
.setDeliveryStatus(cursor.requireInt(STATUS).toLong())
|
||||
.setDeliveryReceiptCount(cursor.requireInt(DELIVERY_RECEIPT_COUNT))
|
||||
.setReadReceiptCount(readReceiptCount)
|
||||
.setHasDeliveryReceipt(cursor.requireBoolean(HAS_DELIVERY_RECEIPT))
|
||||
.setHasReadReceipt(hasReadReceipt)
|
||||
.setExpiresIn(cursor.requireLong(EXPIRES_IN))
|
||||
.setLastSeen(cursor.requireLong(LAST_SEEN))
|
||||
.setSnippetUri(getSnippetUri(cursor))
|
||||
|
||||
@@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V206_AddConversatio
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V207_AddChunkSizeColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V209_ClearRecipientPniFromAciColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V210_FixPniPossibleColumns
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V211_ReceiptColumnRenames
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
@@ -73,7 +74,7 @@ object SignalDatabaseMigrations {
|
||||
|
||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||
|
||||
const val DATABASE_VERSION = 210
|
||||
const val DATABASE_VERSION = 211
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@@ -324,6 +325,10 @@ object SignalDatabaseMigrations {
|
||||
if (oldVersion < 210) {
|
||||
V210_FixPniPossibleColumns.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 211) {
|
||||
V211_ReceiptColumnRenames.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
/**
|
||||
*/
|
||||
@Suppress("ClassName")
|
||||
object V211_ReceiptColumnRenames : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("ALTER TABLE message RENAME COLUMN delivery_receipt_count TO has_delivery_receipt")
|
||||
db.execSQL("ALTER TABLE message RENAME COLUMN read_receipt_count TO has_read_receipt")
|
||||
db.execSQL("ALTER TABLE message RENAME COLUMN viewed_receipt_count TO viewed")
|
||||
|
||||
db.execSQL("ALTER TABLE thread RENAME COLUMN delivery_receipt_count TO has_delivery_receipt")
|
||||
db.execSQL("ALTER TABLE thread RENAME COLUMN read_receipt_count TO has_read_receipt")
|
||||
}
|
||||
}
|
||||
@@ -46,13 +46,13 @@ public abstract class DisplayRecord {
|
||||
private final long threadId;
|
||||
private final String body;
|
||||
private final int deliveryStatus;
|
||||
private final int deliveryReceiptCount;
|
||||
private final int readReceiptCount;
|
||||
private final int viewReceiptCount;
|
||||
private final boolean hasDeliveryReceipt;
|
||||
private final boolean hasReadReceipt;
|
||||
private final boolean viewed;
|
||||
|
||||
DisplayRecord(String body, Recipient fromRecipient, Recipient toRecipient, long dateSent,
|
||||
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long type, int readReceiptCount, int viewReceiptCount)
|
||||
long dateReceived, long threadId, int deliveryStatus, boolean hasDeliveryReceipt,
|
||||
long type, boolean hasReadReceipt, boolean viewed)
|
||||
{
|
||||
this.threadId = threadId;
|
||||
this.fromRecipient = fromRecipient;
|
||||
@@ -61,10 +61,10 @@ public abstract class DisplayRecord {
|
||||
this.dateReceived = dateReceived;
|
||||
this.type = type;
|
||||
this.body = body;
|
||||
this.deliveryReceiptCount = deliveryReceiptCount;
|
||||
this.readReceiptCount = readReceiptCount;
|
||||
this.hasDeliveryReceipt = hasDeliveryReceipt;
|
||||
this.hasReadReceipt = hasReadReceipt;
|
||||
this.viewed = viewed;
|
||||
this.deliveryStatus = deliveryStatus;
|
||||
this.viewReceiptCount = viewReceiptCount;
|
||||
}
|
||||
|
||||
public @NonNull String getBody() {
|
||||
@@ -203,36 +203,25 @@ public abstract class DisplayRecord {
|
||||
return deliveryStatus;
|
||||
}
|
||||
|
||||
public int getDeliveryReceiptCount() {
|
||||
return deliveryReceiptCount;
|
||||
public boolean hasDeliveryReceipt() {
|
||||
return hasDeliveryReceipt;
|
||||
}
|
||||
|
||||
public int getReadReceiptCount() {
|
||||
return readReceiptCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* For outgoing messages, this is incremented whenever a remote recipient has viewed our message
|
||||
* and sends us a VIEWED receipt. For incoming messages, this is an indication of whether local
|
||||
* user has viewed a piece of content.
|
||||
*
|
||||
* @return the number of times this has been viewed.
|
||||
* Either the outgoing message has a viewed receipt, or an incoming message has been viewed by the local user.
|
||||
*/
|
||||
public int getViewedReceiptCount() {
|
||||
return viewReceiptCount;
|
||||
public boolean isViewed() {
|
||||
return viewed;
|
||||
}
|
||||
|
||||
public boolean isDelivered() {
|
||||
return (deliveryStatus >= Status.STATUS_COMPLETE &&
|
||||
deliveryStatus < Status.STATUS_PENDING) || deliveryReceiptCount > 0;
|
||||
deliveryStatus < Status.STATUS_PENDING) || hasDeliveryReceipt;
|
||||
}
|
||||
|
||||
public boolean isRemoteViewed() {
|
||||
return viewReceiptCount > 0;
|
||||
}
|
||||
|
||||
public boolean isRemoteRead() {
|
||||
return readReceiptCount > 0;
|
||||
public boolean hasReadReceipt() {
|
||||
return hasReadReceipt;
|
||||
}
|
||||
|
||||
public boolean isPendingInsecureSmsFallback() {
|
||||
|
||||
@@ -41,19 +41,19 @@ public class InMemoryMessageRecord extends MessageRecord {
|
||||
System.currentTimeMillis(),
|
||||
threadId,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
type,
|
||||
Collections.emptySet(),
|
||||
Collections.emptySet(),
|
||||
-1,
|
||||
0,
|
||||
System.currentTimeMillis(),
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
Collections.emptyList(),
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
-1,
|
||||
null,
|
||||
0);
|
||||
|
||||
@@ -109,25 +109,25 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
|
||||
MessageRecord(long id, String body, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient,
|
||||
long dateSent, long dateReceived, long dateServer, long threadId,
|
||||
int deliveryStatus, int deliveryReceiptCount, long type,
|
||||
int deliveryStatus, boolean hasDeliveryReceipt, long type,
|
||||
Set<IdentityKeyMismatch> mismatches,
|
||||
Set<NetworkFailure> networkFailures,
|
||||
int subscriptionId,
|
||||
long expiresIn,
|
||||
long expireStarted,
|
||||
int readReceiptCount,
|
||||
boolean hasReadReceipt,
|
||||
boolean unidentified,
|
||||
@NonNull List<ReactionRecord> reactions,
|
||||
boolean remoteDelete,
|
||||
long notifiedTimestamp,
|
||||
int viewedReceiptCount,
|
||||
boolean viewed,
|
||||
long receiptTimestamp,
|
||||
@Nullable MessageId originalMessageId,
|
||||
int revisionNumber)
|
||||
{
|
||||
super(body, fromRecipient, toRecipient, dateSent, dateReceived,
|
||||
threadId, deliveryStatus, deliveryReceiptCount, type,
|
||||
readReceiptCount, viewedReceiptCount);
|
||||
threadId, deliveryStatus, hasDeliveryReceipt, type,
|
||||
hasReadReceipt, viewed);
|
||||
this.id = id;
|
||||
this.authorDeviceId = fromDeviceId;
|
||||
this.mismatches = mismatches;
|
||||
|
||||
@@ -78,7 +78,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||
long dateSent,
|
||||
long dateReceived,
|
||||
long dateServer,
|
||||
int deliveryReceiptCount,
|
||||
boolean hasDeliveryReceipt,
|
||||
long threadId,
|
||||
String body,
|
||||
@NonNull SlideDeck slideDeck,
|
||||
@@ -89,7 +89,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||
long expiresIn,
|
||||
long expireStarted,
|
||||
boolean viewOnce,
|
||||
int readReceiptCount,
|
||||
boolean hasReadReceipt,
|
||||
@Nullable Quote quote,
|
||||
@NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> linkPreviews,
|
||||
@@ -98,7 +98,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||
boolean remoteDelete,
|
||||
boolean mentionsSelf,
|
||||
long notifiedTimestamp,
|
||||
int viewedReceiptCount,
|
||||
boolean viewed,
|
||||
long receiptTimestamp,
|
||||
@Nullable BodyRangeList messageRanges,
|
||||
@NonNull StoryType storyType,
|
||||
@@ -112,9 +112,9 @@ public class MmsMessageRecord extends MessageRecord {
|
||||
int revisionNumber)
|
||||
{
|
||||
super(id, body, fromRecipient, fromDeviceId, toRecipient,
|
||||
dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount,
|
||||
mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, readReceiptCount,
|
||||
unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp, originalMessageId, revisionNumber);
|
||||
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;
|
||||
@@ -276,18 +276,18 @@ public class MmsMessageRecord extends MessageRecord {
|
||||
}
|
||||
|
||||
public @NonNull MmsMessageRecord withReactions(@NonNull List<ReactionRecord> reactions) {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MmsMessageRecord withoutQuote() {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
hasReadReceipt(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
@@ -306,27 +306,27 @@ public class MmsMessageRecord extends MessageRecord {
|
||||
List<DatabaseAttachment> slideAttachments = attachments.stream().filter(a -> !contactAttachments.contains(a)).filter(a -> !linkPreviewAttachments.contains(a)).collect(Collectors.toList());
|
||||
SlideDeck slideDeck = MessageTable.MmsReader.buildSlideDeck(slideAttachments);
|
||||
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck,
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), getThreadId(), getBody(), slideDeck,
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
hasReadReceipt(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MmsMessageRecord withPayment(@NonNull Payment payment) {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
|
||||
public @NonNull MmsMessageRecord withCall(@Nullable CallTable.Call call) {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate(), getLatestRevisionId(),
|
||||
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate(), getLatestRevisionId(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import org.thoughtcrime.securesms.database.MessageTypes;
|
||||
final class StatusUtil {
|
||||
private StatusUtil() {}
|
||||
|
||||
static boolean isDelivered(long deliveryStatus, int deliveryReceiptCount) {
|
||||
static boolean isDelivered(long deliveryStatus, boolean hasDeliveryReceipt) {
|
||||
return (deliveryStatus >= MessageTable.Status.STATUS_COMPLETE &&
|
||||
deliveryStatus < MessageTable.Status.STATUS_PENDING) || deliveryReceiptCount > 0;
|
||||
deliveryStatus < MessageTable.Status.STATUS_PENDING) || hasDeliveryReceipt;
|
||||
}
|
||||
|
||||
static boolean isPending(long type) {
|
||||
|
||||
@@ -43,8 +43,8 @@ public final class ThreadRecord {
|
||||
private final long type;
|
||||
private final long date;
|
||||
private final long deliveryStatus;
|
||||
private final int deliveryReceiptCount;
|
||||
private final int readReceiptCount;
|
||||
private final boolean hasDeliveryReceipt;
|
||||
private final boolean hasReadReceipt;
|
||||
private final Uri snippetUri;
|
||||
private final String contentType;
|
||||
private final Extra extra;
|
||||
@@ -65,8 +65,8 @@ public final class ThreadRecord {
|
||||
this.date = builder.date;
|
||||
this.type = builder.type;
|
||||
this.deliveryStatus = builder.deliveryStatus;
|
||||
this.deliveryReceiptCount = builder.deliveryReceiptCount;
|
||||
this.readReceiptCount = builder.readReceiptCount;
|
||||
this.hasDeliveryReceipt = builder.hasDeliveryReceipt;
|
||||
this.hasReadReceipt = builder.hasReadReceipt;
|
||||
this.snippetUri = builder.snippetUri;
|
||||
this.contentType = builder.contentType;
|
||||
this.extra = builder.extra;
|
||||
@@ -173,8 +173,8 @@ public final class ThreadRecord {
|
||||
return StatusUtil.isFailed(type, deliveryStatus);
|
||||
}
|
||||
|
||||
public boolean isRemoteRead() {
|
||||
return readReceiptCount > 0;
|
||||
public boolean hasReadReceipt() {
|
||||
return hasReadReceipt;
|
||||
}
|
||||
|
||||
public boolean isPendingInsecureSmsFallback() {
|
||||
@@ -182,7 +182,7 @@ public final class ThreadRecord {
|
||||
}
|
||||
|
||||
public boolean isDelivered() {
|
||||
return StatusUtil.isDelivered(deliveryStatus, deliveryReceiptCount);
|
||||
return StatusUtil.isDelivered(deliveryStatus, hasDeliveryReceipt);
|
||||
}
|
||||
|
||||
public boolean isScheduledMessage() {
|
||||
@@ -244,8 +244,8 @@ public final class ThreadRecord {
|
||||
type == that.type &&
|
||||
date == that.date &&
|
||||
deliveryStatus == that.deliveryStatus &&
|
||||
deliveryReceiptCount == that.deliveryReceiptCount &&
|
||||
readReceiptCount == that.readReceiptCount &&
|
||||
hasDeliveryReceipt == that.hasDeliveryReceipt &&
|
||||
hasReadReceipt == that.hasReadReceipt &&
|
||||
meaningfulMessages == that.meaningfulMessages &&
|
||||
unreadCount == that.unreadCount &&
|
||||
forcedUnread == that.forcedUnread &&
|
||||
@@ -270,8 +270,8 @@ public final class ThreadRecord {
|
||||
type,
|
||||
date,
|
||||
deliveryStatus,
|
||||
deliveryReceiptCount,
|
||||
readReceiptCount,
|
||||
hasDeliveryReceipt,
|
||||
hasReadReceipt,
|
||||
snippetUri,
|
||||
contentType,
|
||||
extra,
|
||||
@@ -293,8 +293,8 @@ public final class ThreadRecord {
|
||||
private long type;
|
||||
private long date;
|
||||
private long deliveryStatus;
|
||||
private int deliveryReceiptCount;
|
||||
private int readReceiptCount;
|
||||
private boolean hasDeliveryReceipt;
|
||||
private boolean hasReadReceipt;
|
||||
private Uri snippetUri;
|
||||
private String contentType;
|
||||
private Extra extra;
|
||||
@@ -342,13 +342,13 @@ public final class ThreadRecord {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDeliveryReceiptCount(int deliveryReceiptCount) {
|
||||
this.deliveryReceiptCount = deliveryReceiptCount;
|
||||
public Builder setHasDeliveryReceipt(boolean hasDeliveryReceipt) {
|
||||
this.hasDeliveryReceipt = hasDeliveryReceipt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setReadReceiptCount(int readReceiptCount) {
|
||||
this.readReceiptCount = readReceiptCount;
|
||||
public Builder setHasReadReceipt(boolean hasReadReceipt) {
|
||||
this.hasReadReceipt = hasReadReceipt;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -158,8 +158,8 @@ public final class MessageDetailsRepository {
|
||||
}
|
||||
|
||||
private @NonNull RecipientDeliveryStatus.Status getStatusFor(MessageRecord messageRecord) {
|
||||
if (messageRecord.isRemoteViewed()) return RecipientDeliveryStatus.Status.VIEWED;
|
||||
if (messageRecord.isRemoteRead()) return RecipientDeliveryStatus.Status.READ;
|
||||
if (messageRecord.isViewed()) return RecipientDeliveryStatus.Status.VIEWED;
|
||||
if (messageRecord.hasReadReceipt()) return RecipientDeliveryStatus.Status.READ;
|
||||
if (messageRecord.isDelivered()) return RecipientDeliveryStatus.Status.DELIVERED;
|
||||
if (messageRecord.isSent()) return RecipientDeliveryStatus.Status.SENT;
|
||||
if (messageRecord.isPending()) return RecipientDeliveryStatus.Status.PENDING;
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.messages
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import org.signal.core.util.Stopwatch
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.PushProcessEarlyMessagesJob
|
||||
@@ -18,6 +19,10 @@ import org.whispersystems.signalservice.internal.push.Envelope
|
||||
import org.whispersystems.signalservice.internal.push.ReceiptMessage
|
||||
|
||||
object ReceiptMessageProcessor {
|
||||
private val TAG = MessageContentProcessor.TAG
|
||||
|
||||
private const val VERBOSE = false
|
||||
|
||||
fun process(context: Context, senderRecipient: Recipient, envelope: Envelope, content: Content, metadata: EnvelopeMetadata, earlyMessageCacheEntry: EarlyMessageCacheEntry?) {
|
||||
val receiptMessage = content.receiptMessage!!
|
||||
|
||||
@@ -37,8 +42,9 @@ object ReceiptMessageProcessor {
|
||||
senderRecipientId: RecipientId
|
||||
) {
|
||||
log(envelope.timestamp!!, "Processing delivery receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${deliveryReceipt.timestamp.joinToString(", ")}")
|
||||
val stopwatch: Stopwatch? = if (VERBOSE) Stopwatch("delivery-receipt", decimalPlaces = 2) else null
|
||||
|
||||
val missingTargetTimestamps: Set<Long> = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestamp, senderRecipientId, envelope.timestamp!!)
|
||||
val missingTargetTimestamps: Set<Long> = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestamp, senderRecipientId, envelope.timestamp!!, stopwatch)
|
||||
|
||||
for (targetTimestamp in missingTargetTimestamps) {
|
||||
warn(envelope.timestamp!!, "[handleDeliveryReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId")
|
||||
@@ -50,7 +56,12 @@ object ReceiptMessageProcessor {
|
||||
}
|
||||
|
||||
SignalDatabase.pendingPniSignatureMessages.acknowledgeReceipts(senderRecipientId, deliveryReceipt.timestamp, metadata.sourceDeviceId)
|
||||
stopwatch?.split("pni-signatures")
|
||||
|
||||
SignalDatabase.messageLog.deleteEntriesForRecipient(deliveryReceipt.timestamp, senderRecipientId, metadata.sourceDeviceId)
|
||||
stopwatch?.split("msl")
|
||||
|
||||
stopwatch?.stop(TAG)
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
|
||||
@@ -119,7 +119,7 @@ public class ViewOnceMessageView extends LinearLayout {
|
||||
icon.setImageResource(0);
|
||||
showProgress = true;
|
||||
} else if (messageRecord.isOutgoing()) {
|
||||
if (messageRecord.isRemoteViewed()) {
|
||||
if (messageRecord.isViewed()) {
|
||||
iconColor = openedIconColor;
|
||||
text.setText(R.string.RevealableMessageView_viewed);
|
||||
icon.setImageResource(R.drawable.ic_viewed_once_24);
|
||||
|
||||
@@ -105,7 +105,7 @@ class StoriesLandingRepository(context: Context) {
|
||||
private fun createStoriesLandingItemData(sender: Recipient, messageRecords: List<MessageRecord>, sendingCount: Long, failureCount: Long): Observable<StoriesLandingItemData> {
|
||||
val itemDataObservable = Observable.create<StoriesLandingItemData> { emitter ->
|
||||
fun refresh(sender: Recipient) {
|
||||
val primaryIndex = messageRecords.indexOfFirst { !it.isOutgoing && it.viewedReceiptCount == 0 }.takeIf { it > -1 } ?: 0
|
||||
val primaryIndex = messageRecords.indexOfFirst { !it.isOutgoing && !it.isViewed }.takeIf { it > -1 } ?: 0
|
||||
val itemData = StoriesLandingItemData(
|
||||
storyRecipient = sender,
|
||||
storyViewState = StoryViewState.NONE,
|
||||
|
||||
@@ -51,7 +51,7 @@ object MyStoriesItem {
|
||||
override fun areContentsTheSame(newItem: Model): Boolean {
|
||||
return distributionStory == newItem.distributionStory &&
|
||||
!hasStatusChange(newItem) &&
|
||||
distributionStory.messageRecord.viewedReceiptCount == newItem.distributionStory.messageRecord.viewedReceiptCount &&
|
||||
distributionStory.messageRecord.isViewed == newItem.distributionStory.messageRecord.isViewed &&
|
||||
super.areContentsTheSame(newItem)
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ open class StoryViewerPageRepository(context: Context, private val storyViewStat
|
||||
content = getContent(record as MmsMessageRecord),
|
||||
conversationMessage = ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(context, record, recipient),
|
||||
allowsReplies = record.storyType.isStoryWithReplies,
|
||||
hasSelfViewed = storyViewStateCache.getOrPut(record.id, if (record.isOutgoing) true else record.viewedReceiptCount > 0)
|
||||
hasSelfViewed = storyViewStateCache.getOrPut(record.id, if (record.isOutgoing) true else record.isViewed())
|
||||
)
|
||||
|
||||
emitter.onNext(story)
|
||||
|
||||
Reference in New Issue
Block a user