diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt index 49b0eb6679..233b986a2a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt @@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet import org.thoughtcrime.securesms.database.documents.NetworkFailureSet import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil import org.thoughtcrime.securesms.database.model.GroupsV2UpdateMessageConverter +import org.thoughtcrime.securesms.database.model.Mention import org.thoughtcrime.securesms.database.model.ReactionRecord import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context @@ -104,6 +105,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } val reactionsById: Map> = SignalDatabase.reactions.getReactionsForMessages(records.keys) + val mentionsById: Map> = SignalDatabase.mentions.getMentionsForMessages(records.keys) val groupReceiptsById: Map> = SignalDatabase.groupReceipts.getGroupReceiptInfoForMessages(records.keys) for ((id, record) in records) { @@ -232,7 +234,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: Log.w(TAG, "Record missing a body, skipping") continue } - else -> builder.standardMessage = record.toTextMessage(reactionsById[id]) + else -> builder.standardMessage = record.toTextMessage(reactionsById[id], mentions = mentionsById[id]) } buffer += builder.build() @@ -286,12 +288,12 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } } - private fun BackupMessageRecord.toTextMessage(reactionRecords: List?): StandardMessage { + private fun BackupMessageRecord.toTextMessage(reactionRecords: List?, mentions: List?): StandardMessage { return StandardMessage( quote = this.toQuote(), text = Text( body = this.body!!, - bodyRanges = this.bodyRanges?.toBackupBodyRanges() ?: emptyList() + bodyRanges = (this.bodyRanges?.toBackupBodyRanges() ?: emptyList()) + (mentions?.toBackupBodyRanges() ?: emptyList()) ), // TODO Link previews! linkPreview = emptyList(), @@ -319,6 +321,16 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } } + private fun List.toBackupBodyRanges(): List { + return this.map { + BackupBodyRange( + start = it.start, + length = it.length, + mentionAci = SignalDatabase.recipients.getRecord(it.recipientId).aci?.toByteString() + ) + } + } + private fun ByteArray.toBackupBodyRanges(): List { val decoded: BodyRangeList = try { BodyRangeList.ADAPTER.decode(this) @@ -331,7 +343,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: BackupBodyRange( start = it.start, length = it.length, - mentionAci = it.mentionUuid?.let { UuidUtil.parseOrThrow(it) }?.toByteArray()?.toByteString(), + mentionAci = it.mentionUuid?.let { uuid -> UuidUtil.parseOrThrow(uuid) }?.toByteArray()?.toByteString(), style = it.style?.toBackupBodyRangeStyle() ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt index 4228bdf28d..3fe1131b80 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt @@ -28,10 +28,12 @@ import org.thoughtcrime.securesms.database.MessageTable import org.thoughtcrime.securesms.database.MessageTypes import org.thoughtcrime.securesms.database.ReactionTable import org.thoughtcrime.securesms.database.SQLiteDatabase +import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet import org.thoughtcrime.securesms.database.documents.NetworkFailure import org.thoughtcrime.securesms.database.documents.NetworkFailureSet +import org.thoughtcrime.securesms.database.model.Mention import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList import org.thoughtcrime.securesms.database.model.databaseprotos.GV2UpdateDescription import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras @@ -42,6 +44,7 @@ import org.thoughtcrime.securesms.mms.QuoteModel import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.JsonUtils +import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.util.UuidUtil /** @@ -205,6 +208,27 @@ class ChatItemImportInserter( } } } + if (this.standardMessage != null) { + val bodyRanges = this.standardMessage.text?.bodyRanges + if (!bodyRanges.isNullOrEmpty()) { + val mentions = bodyRanges.filter { it.mentionAci != null && it.start != null && it.length != null } + .mapNotNull { + val aci = ServiceId.ACI.parseOrNull(it.mentionAci!!) + + if (aci != null && !aci.isUnknown) { + val id = RecipientId.from(aci) + Mention(id, it.start!!, it.length!!) + } else { + null + } + } + if (mentions.isNotEmpty()) { + followUp = { messageId -> + SignalDatabase.mentions.insert(threadId, messageId, mentions) + } + } + } + } return MessageInsert(contentValues, followUp) } @@ -345,7 +369,7 @@ class ChatItemImportInserter( this.put(MessageTable.BODY, standardMessage.text.body) if (standardMessage.text.bodyRanges.isNotEmpty()) { - this.put(MessageTable.MESSAGE_RANGES, standardMessage.text.bodyRanges.toLocalBodyRanges()?.encode() as ByteArray?) + this.put(MessageTable.MESSAGE_RANGES, standardMessage.text.bodyRanges.toLocalBodyRanges()?.encode()) } }