mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 09:49:30 +01:00
Merge MediaMmsMessageRecord into MmsMessageRecord.
This commit is contained in:
@@ -89,7 +89,6 @@ 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.GroupCallUpdateDetailsUtil
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.Mention
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus
|
||||
import org.thoughtcrime.securesms.database.model.MessageId
|
||||
@@ -964,7 +963,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
}
|
||||
}
|
||||
|
||||
fun insertEditMessageInbox(mediaMessage: IncomingMessage, targetMessage: MediaMmsMessageRecord): Optional<InsertResult> {
|
||||
fun insertEditMessageInbox(mediaMessage: IncomingMessage, targetMessage: MmsMessageRecord): Optional<InsertResult> {
|
||||
val insertResult = insertMessageInbox(retrieved = mediaMessage, editedMessage = targetMessage, notifyObservers = false)
|
||||
|
||||
if (insertResult.isPresent) {
|
||||
@@ -1924,7 +1923,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
fun markAsRemoteDelete(targetMessage: MessageRecord) {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
if (targetMessage.isEditMessage) {
|
||||
val latestRevisionId = (targetMessage as? MediaMmsMessageRecord)?.latestRevisionId?.id ?: targetMessage.id
|
||||
val latestRevisionId = (targetMessage as? MmsMessageRecord)?.latestRevisionId?.id ?: targetMessage.id
|
||||
markAsRemoteDeleteInternal(latestRevisionId)
|
||||
getPreviousEditIds(latestRevisionId).map { id ->
|
||||
db.update(TABLE_NAME)
|
||||
@@ -2445,7 +2444,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
fun insertMessageInbox(
|
||||
retrieved: IncomingMessage,
|
||||
candidateThreadId: Long = -1,
|
||||
editedMessage: MediaMmsMessageRecord? = null,
|
||||
editedMessage: MmsMessageRecord? = null,
|
||||
notifyObservers: Boolean = true
|
||||
): Optional<InsertResult> {
|
||||
val type = retrieved.toMessageType()
|
||||
@@ -2924,8 +2923,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
.where("$ID_WHERE OR $LATEST_REVISION_ID = ?", message.messageToEdit, message.messageToEdit)
|
||||
.run()
|
||||
|
||||
val textAttachments = (editedMessage as? MediaMmsMessageRecord)?.slideDeck?.asAttachments()?.filter { it.contentType == MediaUtil.LONG_TEXT }?.mapNotNull { (it as? DatabaseAttachment)?.attachmentId?.rowId } ?: emptyList()
|
||||
val linkPreviewAttachments = (editedMessage as? MediaMmsMessageRecord)?.linkPreviews?.mapNotNull { it.attachmentId?.rowId } ?: emptyList()
|
||||
val textAttachments = (editedMessage as? MmsMessageRecord)?.slideDeck?.asAttachments()?.filter { it.contentType == MediaUtil.LONG_TEXT }?.mapNotNull { (it as? DatabaseAttachment)?.attachmentId?.rowId } ?: emptyList()
|
||||
val linkPreviewAttachments = (editedMessage as? MmsMessageRecord)?.linkPreviews?.mapNotNull { it.attachmentId?.rowId } ?: emptyList()
|
||||
val excludeIds = HashSet<Long>()
|
||||
excludeIds += textAttachments
|
||||
excludeIds += linkPreviewAttachments
|
||||
@@ -4933,7 +4932,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
return MessageId(cursor.requireLong(ID))
|
||||
}
|
||||
|
||||
private fun getMediaMmsMessageRecord(cursor: Cursor): MediaMmsMessageRecord {
|
||||
private fun getMediaMmsMessageRecord(cursor: Cursor): MmsMessageRecord {
|
||||
val id = cursor.requireLong(ID)
|
||||
val dateSent = cursor.requireLong(DATE_SENT)
|
||||
val dateReceived = cursor.requireLong(DATE_RECEIVED)
|
||||
@@ -5012,7 +5011,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
null
|
||||
}
|
||||
|
||||
return MediaMmsMessageRecord(
|
||||
return MmsMessageRecord(
|
||||
id,
|
||||
fromRecipient,
|
||||
fromDeviceId,
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.signal.core.util.CursorUtil;
|
||||
import org.signal.core.util.SQLiteDatabaseExtensionsKt;
|
||||
import org.signal.core.util.SqlUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.CryptoValue;
|
||||
@@ -436,8 +436,8 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData
|
||||
public @NonNull MessageRecord updateMessageWithPayment(@NonNull MessageRecord record) {
|
||||
if (record.isPaymentNotification()) {
|
||||
Payment payment = getPayment(UuidUtil.parseOrThrow(record.getBody()));
|
||||
if (payment != null && record instanceof MediaMmsMessageRecord) {
|
||||
return ((MediaMmsMessageRecord) record).withPayment(payment);
|
||||
if (payment != null && record instanceof MmsMessageRecord) {
|
||||
return ((MmsMessageRecord) record).withPayment(payment);
|
||||
} else {
|
||||
throw new AssertionError("Payment not found for message");
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import org.thoughtcrime.securesms.database.SignalDatabase.Companion.messageLog
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.messages
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.recipients
|
||||
import org.thoughtcrime.securesms.database.ThreadBodyUtil.ThreadBody
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||
@@ -1699,7 +1698,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
return null
|
||||
}
|
||||
|
||||
val slideDeck: SlideDeck = (record as MediaMmsMessageRecord).slideDeck
|
||||
val slideDeck: SlideDeck = (record as MmsMessageRecord).slideDeck
|
||||
val thumbnail = Optional.ofNullable(slideDeck.thumbnailSlide)
|
||||
.or(Optional.ofNullable(slideDeck.stickerSlide))
|
||||
.orElse(null)
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2012 Moxie Marlinspike
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.SpannableString;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.database.CallTable;
|
||||
import org.thoughtcrime.securesms.database.MessageTable;
|
||||
import org.thoughtcrime.securesms.database.MessageTable.Status;
|
||||
import org.thoughtcrime.securesms.database.MessageTypes;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.payments.Payment;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.whispersystems.signalservice.api.payments.FormatterOptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents the message record model for MMS messages that contain
|
||||
* media (ie: they've been downloaded).
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*
|
||||
*/
|
||||
|
||||
public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
private final static String TAG = Log.tag(MediaMmsMessageRecord.class);
|
||||
|
||||
private final boolean mentionsSelf;
|
||||
private final BodyRangeList messageRanges;
|
||||
private final Payment payment;
|
||||
private final CallTable.Call call;
|
||||
private final long scheduledDate;
|
||||
private final MessageId latestRevisionId;
|
||||
|
||||
public MediaMmsMessageRecord(long id,
|
||||
Recipient fromRecipient,
|
||||
int fromDeviceId,
|
||||
Recipient toRecipient,
|
||||
long dateSent,
|
||||
long dateReceived,
|
||||
long dateServer,
|
||||
int deliveryReceiptCount,
|
||||
long threadId,
|
||||
String body,
|
||||
@NonNull SlideDeck slideDeck,
|
||||
long mailbox,
|
||||
Set<IdentityKeyMismatch> mismatches,
|
||||
Set<NetworkFailure> failures,
|
||||
int subscriptionId,
|
||||
long expiresIn,
|
||||
long expireStarted,
|
||||
boolean viewOnce,
|
||||
int readReceiptCount,
|
||||
@Nullable Quote quote,
|
||||
@NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> linkPreviews,
|
||||
boolean unidentified,
|
||||
@NonNull List<ReactionRecord> reactions,
|
||||
boolean remoteDelete,
|
||||
boolean mentionsSelf,
|
||||
long notifiedTimestamp,
|
||||
int viewedReceiptCount,
|
||||
long receiptTimestamp,
|
||||
@Nullable BodyRangeList messageRanges,
|
||||
@NonNull StoryType storyType,
|
||||
@Nullable ParentStoryId parentStoryId,
|
||||
@Nullable GiftBadge giftBadge,
|
||||
@Nullable Payment payment,
|
||||
@Nullable CallTable.Call call,
|
||||
long scheduledDate,
|
||||
@Nullable MessageId latestRevisionId,
|
||||
@Nullable MessageId originalMessageId,
|
||||
int revisionNumber)
|
||||
{
|
||||
super(id, body, fromRecipient, fromDeviceId, toRecipient, dateSent,
|
||||
dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
|
||||
subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck,
|
||||
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp,
|
||||
storyType, parentStoryId, giftBadge, originalMessageId, revisionNumber);
|
||||
this.mentionsSelf = mentionsSelf;
|
||||
this.messageRanges = messageRanges;
|
||||
this.payment = payment;
|
||||
this.call = call;
|
||||
this.scheduledDate = scheduledDate;
|
||||
this.latestRevisionId = latestRevisionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSelfMention() {
|
||||
return mentionsSelf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMmsNotification() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@WorkerThread
|
||||
public SpannableString getDisplayBody(@NonNull Context context) {
|
||||
if (MessageTypes.isChatSessionRefresh(type)) {
|
||||
return emphasisAdded(context.getString(R.string.MmsMessageRecord_bad_encrypted_mms_message));
|
||||
} else if (MessageTypes.isDuplicateMessageType(type)) {
|
||||
return emphasisAdded(context.getString(R.string.SmsMessageRecord_duplicate_message));
|
||||
} else if (MessageTypes.isNoRemoteSessionType(type)) {
|
||||
return emphasisAdded(context.getString(R.string.MmsMessageRecord_mms_message_encrypted_for_non_existing_session));
|
||||
} else if (isLegacyMessage()) {
|
||||
return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported));
|
||||
} else if (isPaymentNotification() && payment != null) {
|
||||
return new SpannableString(context.getString(R.string.MessageRecord__payment_s, payment.getAmount().toString(FormatterOptions.defaults())));
|
||||
}
|
||||
|
||||
return super.getDisplayBody(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UpdateDescription getUpdateDisplayBody(@NonNull Context context, @Nullable Consumer<RecipientId> recipientClickHandler) {
|
||||
if (isCallLog() && call != null && !(call.getType() == CallTable.Type.GROUP_CALL)) {
|
||||
boolean accepted = call.getEvent() == CallTable.Event.ACCEPTED;
|
||||
String callDateString = getCallDateString(context);
|
||||
|
||||
if (call.getDirection() == CallTable.Direction.OUTGOING) {
|
||||
if (call.getType() == CallTable.Type.AUDIO_CALL) {
|
||||
int updateString = accepted ? R.string.MessageRecord_outgoing_voice_call : R.string.MessageRecord_unanswered_voice_call;
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), R.drawable.ic_update_audio_call_outgoing_16);
|
||||
} else {
|
||||
int updateString = accepted ? R.string.MessageRecord_outgoing_video_call : R.string.MessageRecord_unanswered_video_call;
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), R.drawable.ic_update_video_call_outgoing_16);
|
||||
}
|
||||
} else {
|
||||
boolean isVideoCall = call.getType() == CallTable.Type.VIDEO_CALL;
|
||||
boolean isMissed = call.getEvent() == CallTable.Event.MISSED;
|
||||
|
||||
if (accepted) {
|
||||
int updateString = isVideoCall ? R.string.MessageRecord_incoming_video_call : R.string.MessageRecord_incoming_voice_call;
|
||||
int icon = isVideoCall ? R.drawable.ic_update_video_call_incoming_16 : R.drawable.ic_update_audio_call_incoming_16;
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), icon);
|
||||
} else if (isMissed) {
|
||||
return isVideoCall ? staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_video_call), callDateString), R.drawable.ic_update_video_call_missed_16, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red))
|
||||
: staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_voice_call), callDateString), R.drawable.ic_update_audio_call_missed_16, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red));
|
||||
} else {
|
||||
return isVideoCall ? staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_you_declined_a_video_call), callDateString), R.drawable.ic_update_video_call_incoming_16)
|
||||
: staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_you_declined_a_voice_call), callDateString), R.drawable.ic_update_audio_call_incoming_16);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.getUpdateDisplayBody(context, recipientClickHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BodyRangeList getMessageRanges() {
|
||||
return messageRanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull BodyRangeList requireMessageRanges() {
|
||||
return Objects.requireNonNull(messageRanges);
|
||||
}
|
||||
|
||||
public @Nullable Payment getPayment() {
|
||||
return payment;
|
||||
}
|
||||
|
||||
public @Nullable CallTable.Call getCall() {
|
||||
return call;
|
||||
}
|
||||
|
||||
public long getScheduledDate() {
|
||||
return scheduledDate;
|
||||
}
|
||||
|
||||
public @Nullable MessageId getLatestRevisionId() {
|
||||
return latestRevisionId;
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withReactions(@NonNull List<ReactionRecord> reactions) {
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withoutQuote() {
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withAttachments(@NonNull List<DatabaseAttachment> attachments) {
|
||||
Map<AttachmentId, DatabaseAttachment> attachmentIdMap = new HashMap<>();
|
||||
for (DatabaseAttachment attachment : attachments) {
|
||||
attachmentIdMap.put(attachment.getAttachmentId(), attachment);
|
||||
}
|
||||
|
||||
List<Contact> contacts = updateContacts(getSharedContacts(), attachmentIdMap);
|
||||
Set<Attachment> contactAttachments = contacts.stream().map(Contact::getAvatarAttachment).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
List<LinkPreview> linkPreviews = updateLinkPreviews(getLinkPreviews(), attachmentIdMap);
|
||||
Set<Attachment> linkPreviewAttachments = linkPreviews.stream().map(LinkPreview::getThumbnail).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
|
||||
Quote quote = updateQuote(getQuote(), attachments);
|
||||
|
||||
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 MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withPayment(@NonNull Payment payment) {
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withCall(@Nullable CallTable.Call call) {
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
private static @NonNull List<Contact> updateContacts(@NonNull List<Contact> contacts, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
|
||||
return contacts.stream()
|
||||
.map(contact -> {
|
||||
if (contact.getAvatar() != null) {
|
||||
DatabaseAttachment attachment = attachmentIdMap.get(contact.getAvatar().getAttachmentId());
|
||||
Contact.Avatar updatedAvatar = new Contact.Avatar(contact.getAvatar().getAttachmentId(),
|
||||
attachment,
|
||||
contact.getAvatar().isProfile());
|
||||
|
||||
return new Contact(contact, updatedAvatar);
|
||||
} else {
|
||||
return contact;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static @NonNull List<LinkPreview> updateLinkPreviews(@NonNull List<LinkPreview> linkPreviews, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
|
||||
return linkPreviews.stream()
|
||||
.map(preview -> {
|
||||
if (preview.getAttachmentId() != null) {
|
||||
DatabaseAttachment attachment = attachmentIdMap.get(preview.getAttachmentId());
|
||||
if (attachment != null) {
|
||||
return new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), preview.getDate(), attachment);
|
||||
} else {
|
||||
return preview;
|
||||
}
|
||||
} else {
|
||||
return preview;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static @Nullable Quote updateQuote(@Nullable Quote quote, @NonNull List<DatabaseAttachment> attachments) {
|
||||
if (quote == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<DatabaseAttachment> quoteAttachments = attachments.stream().filter(Attachment::isQuote).collect(Collectors.toList());
|
||||
|
||||
return quote.withAttachment(new SlideDeck(quoteAttachments));
|
||||
}
|
||||
}
|
||||
@@ -735,8 +735,8 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
}
|
||||
|
||||
public boolean isLatestRevision() {
|
||||
if (this instanceof MediaMmsMessageRecord) {
|
||||
return ((MediaMmsMessageRecord) this).getLatestRevisionId() == null;
|
||||
if (this instanceof MmsMessageRecord) {
|
||||
return ((MmsMessageRecord) this).getLatestRevisionId() == null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.database.CallTable
|
||||
import org.thoughtcrime.securesms.payments.Payment
|
||||
|
||||
fun MessageRecord.withReactions(reactions: List<ReactionRecord>): MessageRecord {
|
||||
return if (this is MediaMmsMessageRecord) {
|
||||
return if (this is MmsMessageRecord) {
|
||||
this.withReactions(reactions)
|
||||
} else {
|
||||
this
|
||||
@@ -18,14 +18,14 @@ fun MessageRecord.withReactions(reactions: List<ReactionRecord>): MessageRecord
|
||||
}
|
||||
|
||||
fun MessageRecord.withAttachments(attachments: List<DatabaseAttachment>): MessageRecord {
|
||||
return if (this is MediaMmsMessageRecord) {
|
||||
return if (this is MmsMessageRecord) {
|
||||
this.withAttachments(attachments)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
fun MessageRecord.withPayment(payment: Payment): MessageRecord {
|
||||
return if (this is MediaMmsMessageRecord) {
|
||||
return if (this is MmsMessageRecord) {
|
||||
this.withPayment(payment)
|
||||
} else {
|
||||
this
|
||||
@@ -33,7 +33,7 @@ fun MessageRecord.withPayment(payment: Payment): MessageRecord {
|
||||
}
|
||||
|
||||
fun MessageRecord.withCall(call: CallTable.Call): MessageRecord {
|
||||
return if (this is MediaMmsMessageRecord) {
|
||||
return if (this is MmsMessageRecord) {
|
||||
this.withCall(call)
|
||||
} else {
|
||||
this
|
||||
|
||||
@@ -1,63 +1,138 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.SpannableString;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.database.CallTable;
|
||||
import org.thoughtcrime.securesms.database.MessageTable;
|
||||
import org.thoughtcrime.securesms.database.MessageTable.Status;
|
||||
import org.thoughtcrime.securesms.database.MessageTypes;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.payments.Payment;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.whispersystems.signalservice.api.payments.FormatterOptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class MmsMessageRecord extends MessageRecord {
|
||||
/**
|
||||
* Represents the message record model for MMS messages that contain
|
||||
* media (ie: they've been downloaded).
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*
|
||||
*/
|
||||
|
||||
private final @NonNull SlideDeck slideDeck;
|
||||
private final @Nullable Quote quote;
|
||||
private final @NonNull List<Contact> contacts = new LinkedList<>();
|
||||
private final @NonNull List<LinkPreview> linkPreviews = new LinkedList<>();
|
||||
private final @NonNull StoryType storyType;
|
||||
private final @Nullable ParentStoryId parentStoryId;
|
||||
private final @Nullable GiftBadge giftBadge;
|
||||
public class MmsMessageRecord extends MessageRecord {
|
||||
private final static String TAG = Log.tag(MmsMessageRecord.class);
|
||||
|
||||
private final boolean viewOnce;
|
||||
private final SlideDeck slideDeck;
|
||||
private final Quote quote;
|
||||
private final List<Contact> contacts = new LinkedList<>();
|
||||
private final List<LinkPreview> linkPreviews = new LinkedList<>();
|
||||
private final StoryType storyType;
|
||||
private final ParentStoryId parentStoryId;
|
||||
private final GiftBadge giftBadge;
|
||||
private final boolean viewOnce;
|
||||
|
||||
private final boolean mentionsSelf;
|
||||
private final BodyRangeList messageRanges;
|
||||
private final Payment payment;
|
||||
private final CallTable.Call call;
|
||||
private final long scheduledDate;
|
||||
private final MessageId latestRevisionId;
|
||||
|
||||
MmsMessageRecord(long id, String body, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient, long dateSent,
|
||||
long dateReceived, long dateServer, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long type, Set<IdentityKeyMismatch> mismatches,
|
||||
Set<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
||||
long expireStarted, boolean viewOnce,
|
||||
@NonNull SlideDeck slideDeck, int readReceiptCount,
|
||||
@Nullable Quote quote, @NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> linkPreviews, boolean unidentified,
|
||||
@NonNull List<ReactionRecord> reactions, boolean remoteDelete, long notifiedTimestamp,
|
||||
int viewedReceiptCount, long receiptTimestamp, @NonNull StoryType storyType,
|
||||
@Nullable ParentStoryId parentStoryId, @Nullable GiftBadge giftBadge, @Nullable MessageId originalMessageId,
|
||||
int revisionNumber)
|
||||
public MmsMessageRecord(long id,
|
||||
Recipient fromRecipient,
|
||||
int fromDeviceId,
|
||||
Recipient toRecipient,
|
||||
long dateSent,
|
||||
long dateReceived,
|
||||
long dateServer,
|
||||
int deliveryReceiptCount,
|
||||
long threadId,
|
||||
String body,
|
||||
@NonNull SlideDeck slideDeck,
|
||||
long mailbox,
|
||||
Set<IdentityKeyMismatch> mismatches,
|
||||
Set<NetworkFailure> failures,
|
||||
int subscriptionId,
|
||||
long expiresIn,
|
||||
long expireStarted,
|
||||
boolean viewOnce,
|
||||
int readReceiptCount,
|
||||
@Nullable Quote quote,
|
||||
@NonNull List<Contact> contacts,
|
||||
@NonNull List<LinkPreview> linkPreviews,
|
||||
boolean unidentified,
|
||||
@NonNull List<ReactionRecord> reactions,
|
||||
boolean remoteDelete,
|
||||
boolean mentionsSelf,
|
||||
long notifiedTimestamp,
|
||||
int viewedReceiptCount,
|
||||
long receiptTimestamp,
|
||||
@Nullable BodyRangeList messageRanges,
|
||||
@NonNull StoryType storyType,
|
||||
@Nullable ParentStoryId parentStoryId,
|
||||
@Nullable GiftBadge giftBadge,
|
||||
@Nullable Payment payment,
|
||||
@Nullable CallTable.Call call,
|
||||
long scheduledDate,
|
||||
@Nullable MessageId latestRevisionId,
|
||||
@Nullable MessageId originalMessageId,
|
||||
int revisionNumber)
|
||||
{
|
||||
super(id, body, fromRecipient, fromDeviceId, toRecipient,
|
||||
dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount,
|
||||
type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount,
|
||||
dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount,
|
||||
mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, readReceiptCount,
|
||||
unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp, originalMessageId, revisionNumber);
|
||||
|
||||
this.slideDeck = slideDeck;
|
||||
this.quote = quote;
|
||||
this.viewOnce = viewOnce;
|
||||
this.storyType = storyType;
|
||||
this.parentStoryId = parentStoryId;
|
||||
this.giftBadge = giftBadge;
|
||||
|
||||
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.contacts.addAll(contacts);
|
||||
this.linkPreviews.addAll(linkPreviews);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isMms() {
|
||||
return true;
|
||||
@@ -111,4 +186,191 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
||||
public @Nullable GiftBadge getGiftBadge() {
|
||||
return giftBadge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSelfMention() {
|
||||
return mentionsSelf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMmsNotification() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@WorkerThread
|
||||
public SpannableString getDisplayBody(@NonNull Context context) {
|
||||
if (MessageTypes.isChatSessionRefresh(type)) {
|
||||
return emphasisAdded(context.getString(R.string.MmsMessageRecord_bad_encrypted_mms_message));
|
||||
} else if (MessageTypes.isDuplicateMessageType(type)) {
|
||||
return emphasisAdded(context.getString(R.string.SmsMessageRecord_duplicate_message));
|
||||
} else if (MessageTypes.isNoRemoteSessionType(type)) {
|
||||
return emphasisAdded(context.getString(R.string.MmsMessageRecord_mms_message_encrypted_for_non_existing_session));
|
||||
} else if (isLegacyMessage()) {
|
||||
return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported));
|
||||
} else if (isPaymentNotification() && payment != null) {
|
||||
return new SpannableString(context.getString(R.string.MessageRecord__payment_s, payment.getAmount().toString(FormatterOptions.defaults())));
|
||||
}
|
||||
|
||||
return super.getDisplayBody(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UpdateDescription getUpdateDisplayBody(@NonNull Context context, @Nullable Consumer<RecipientId> recipientClickHandler) {
|
||||
if (isCallLog() && call != null && !(call.getType() == CallTable.Type.GROUP_CALL)) {
|
||||
boolean accepted = call.getEvent() == CallTable.Event.ACCEPTED;
|
||||
String callDateString = getCallDateString(context);
|
||||
|
||||
if (call.getDirection() == CallTable.Direction.OUTGOING) {
|
||||
if (call.getType() == CallTable.Type.AUDIO_CALL) {
|
||||
int updateString = accepted ? R.string.MessageRecord_outgoing_voice_call : R.string.MessageRecord_unanswered_voice_call;
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), R.drawable.ic_update_audio_call_outgoing_16);
|
||||
} else {
|
||||
int updateString = accepted ? R.string.MessageRecord_outgoing_video_call : R.string.MessageRecord_unanswered_video_call;
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), R.drawable.ic_update_video_call_outgoing_16);
|
||||
}
|
||||
} else {
|
||||
boolean isVideoCall = call.getType() == CallTable.Type.VIDEO_CALL;
|
||||
boolean isMissed = call.getEvent() == CallTable.Event.MISSED;
|
||||
|
||||
if (accepted) {
|
||||
int updateString = isVideoCall ? R.string.MessageRecord_incoming_video_call : R.string.MessageRecord_incoming_voice_call;
|
||||
int icon = isVideoCall ? R.drawable.ic_update_video_call_incoming_16 : R.drawable.ic_update_audio_call_incoming_16;
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), icon);
|
||||
} else if (isMissed) {
|
||||
return isVideoCall ? staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_video_call), callDateString), R.drawable.ic_update_video_call_missed_16, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red))
|
||||
: staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_voice_call), callDateString), R.drawable.ic_update_audio_call_missed_16, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red));
|
||||
} else {
|
||||
return isVideoCall ? staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_you_declined_a_video_call), callDateString), R.drawable.ic_update_video_call_incoming_16)
|
||||
: staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_you_declined_a_voice_call), callDateString), R.drawable.ic_update_audio_call_incoming_16);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.getUpdateDisplayBody(context, recipientClickHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BodyRangeList getMessageRanges() {
|
||||
return messageRanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull BodyRangeList requireMessageRanges() {
|
||||
return Objects.requireNonNull(messageRanges);
|
||||
}
|
||||
|
||||
public @Nullable Payment getPayment() {
|
||||
return payment;
|
||||
}
|
||||
|
||||
public @Nullable CallTable.Call getCall() {
|
||||
return call;
|
||||
}
|
||||
|
||||
public long getScheduledDate() {
|
||||
return scheduledDate;
|
||||
}
|
||||
|
||||
public @Nullable MessageId getLatestRevisionId() {
|
||||
return latestRevisionId;
|
||||
}
|
||||
|
||||
public @NonNull MmsMessageRecord withReactions(@NonNull List<ReactionRecord> reactions) {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MmsMessageRecord withoutQuote() {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MmsMessageRecord withAttachments(@NonNull List<DatabaseAttachment> attachments) {
|
||||
Map<AttachmentId, DatabaseAttachment> attachmentIdMap = new HashMap<>();
|
||||
for (DatabaseAttachment attachment : attachments) {
|
||||
attachmentIdMap.put(attachment.getAttachmentId(), attachment);
|
||||
}
|
||||
|
||||
List<Contact> contacts = updateContacts(getSharedContacts(), attachmentIdMap);
|
||||
Set<Attachment> contactAttachments = contacts.stream().map(Contact::getAvatarAttachment).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
List<LinkPreview> linkPreviews = updateLinkPreviews(getLinkPreviews(), attachmentIdMap);
|
||||
Set<Attachment> linkPreviewAttachments = linkPreviews.stream().map(LinkPreview::getThumbnail).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
|
||||
Quote quote = updateQuote(getQuote(), attachments);
|
||||
|
||||
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,
|
||||
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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
public @NonNull MmsMessageRecord withPayment(@NonNull Payment payment) {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
|
||||
public @NonNull MmsMessageRecord withCall(@Nullable CallTable.Call call) {
|
||||
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), 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(),
|
||||
getOriginalMessageId(), getRevisionNumber());
|
||||
}
|
||||
|
||||
private static @NonNull List<Contact> updateContacts(@NonNull List<Contact> contacts, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
|
||||
return contacts.stream()
|
||||
.map(contact -> {
|
||||
if (contact.getAvatar() != null) {
|
||||
DatabaseAttachment attachment = attachmentIdMap.get(contact.getAvatar().getAttachmentId());
|
||||
Contact.Avatar updatedAvatar = new Contact.Avatar(contact.getAvatar().getAttachmentId(),
|
||||
attachment,
|
||||
contact.getAvatar().isProfile());
|
||||
|
||||
return new Contact(contact, updatedAvatar);
|
||||
} else {
|
||||
return contact;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static @NonNull List<LinkPreview> updateLinkPreviews(@NonNull List<LinkPreview> linkPreviews, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
|
||||
return linkPreviews.stream()
|
||||
.map(preview -> {
|
||||
if (preview.getAttachmentId() != null) {
|
||||
DatabaseAttachment attachment = attachmentIdMap.get(preview.getAttachmentId());
|
||||
if (attachment != null) {
|
||||
return new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), preview.getDate(), attachment);
|
||||
} else {
|
||||
return preview;
|
||||
}
|
||||
} else {
|
||||
return preview;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static @Nullable Quote updateQuote(@Nullable Quote quote, @NonNull List<DatabaseAttachment> attachments) {
|
||||
if (quote == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<DatabaseAttachment> quoteAttachments = attachments.stream().filter(Attachment::isQuote).collect(Collectors.toList());
|
||||
|
||||
return quote.withAttachment(new SlideDeck(quoteAttachments));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user