Convert gv2 update messages to backup distinct protos.
This commit is contained in:
parent
0036b8e2d6
commit
98865d61dd
15 changed files with 1019 additions and 81 deletions
|
@ -118,7 +118,8 @@ class ConversationElementGenerator {
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
val conversationMessage = ConversationMessageFactory.createWithUnresolvedData(
|
val conversationMessage = ConversationMessageFactory.createWithUnresolvedData(
|
||||||
|
|
|
@ -84,7 +84,12 @@ abstract class ConversationListDataSource implements PagedDataSource<Long, Conve
|
||||||
if (!MessageTypes.isGroupV2(record.getType())) {
|
if (!MessageTypes.isGroupV2(record.getType())) {
|
||||||
needsResolve.add(record.getRecipient().getId());
|
needsResolve.add(record.getRecipient().getId());
|
||||||
} else if (MessageTypes.isGroupUpdate(record.getType())) {
|
} else if (MessageTypes.isGroupUpdate(record.getType())) {
|
||||||
UpdateDescription description = MessageRecord.getGv2ChangeDescription(ApplicationDependencies.getApplication(), record.getBody(), null);
|
UpdateDescription description;
|
||||||
|
if (record.getMessageExtras() != null) {
|
||||||
|
description = MessageRecord.getGv2ChangeDescription(ApplicationDependencies.getApplication(), record.getMessageExtras(), null);
|
||||||
|
} else {
|
||||||
|
description = MessageRecord.getGv2ChangeDescription(ApplicationDependencies.getApplication(), record.getBody(), null);
|
||||||
|
}
|
||||||
needsResolve.addAll(description.getMentioned().stream().map(RecipientId::from).collect(Collectors.toList()));
|
needsResolve.addAll(description.getMentioned().stream().map(RecipientId::from).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -572,7 +572,11 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
|
||||||
}
|
}
|
||||||
} else if (MessageTypes.isGroupUpdate(thread.getType())) {
|
} else if (MessageTypes.isGroupUpdate(thread.getType())) {
|
||||||
if (thread.getRecipient().isPushV2Group()) {
|
if (thread.getRecipient().isPushV2Group()) {
|
||||||
|
if (thread.getMessageExtras() != null) {
|
||||||
|
return emphasisAdded(context, MessageRecord.getGv2ChangeDescription(context, thread.getMessageExtras(), null), defaultTint);
|
||||||
|
} else {
|
||||||
return emphasisAdded(context, MessageRecord.getGv2ChangeDescription(context, thread.getBody(), null), defaultTint);
|
return emphasisAdded(context, MessageRecord.getGv2ChangeDescription(context, thread.getBody(), null), defaultTint);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return emphasisAdded(context, context.getString(R.string.ThreadRecord_group_updated), R.drawable.ic_update_group_16, defaultTint);
|
return emphasisAdded(context, context.getString(R.string.ThreadRecord_group_updated), R.drawable.ic_update_group_16, defaultTint);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails
|
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState
|
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState
|
||||||
|
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails
|
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchoverEvent
|
import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchoverEvent
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent
|
import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent
|
||||||
|
@ -207,6 +208,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||||
const val LATEST_REVISION_ID = "latest_revision_id"
|
const val LATEST_REVISION_ID = "latest_revision_id"
|
||||||
const val ORIGINAL_MESSAGE_ID = "original_message_id"
|
const val ORIGINAL_MESSAGE_ID = "original_message_id"
|
||||||
const val REVISION_NUMBER = "revision_number"
|
const val REVISION_NUMBER = "revision_number"
|
||||||
|
const val MESSAGE_EXTRAS = "message_extras"
|
||||||
|
|
||||||
const val QUOTE_NOT_PRESENT_ID = 0L
|
const val QUOTE_NOT_PRESENT_ID = 0L
|
||||||
const val QUOTE_TARGET_MISSING_ID = -1L
|
const val QUOTE_TARGET_MISSING_ID = -1L
|
||||||
|
@ -264,7 +266,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||||
$SCHEDULED_DATE INTEGER DEFAULT -1,
|
$SCHEDULED_DATE INTEGER DEFAULT -1,
|
||||||
$LATEST_REVISION_ID INTEGER DEFAULT NULL REFERENCES $TABLE_NAME ($ID) ON DELETE CASCADE,
|
$LATEST_REVISION_ID INTEGER DEFAULT NULL REFERENCES $TABLE_NAME ($ID) ON DELETE CASCADE,
|
||||||
$ORIGINAL_MESSAGE_ID INTEGER DEFAULT NULL REFERENCES $TABLE_NAME ($ID) ON DELETE CASCADE,
|
$ORIGINAL_MESSAGE_ID INTEGER DEFAULT NULL REFERENCES $TABLE_NAME ($ID) ON DELETE CASCADE,
|
||||||
$REVISION_NUMBER INTEGER DEFAULT 0
|
$REVISION_NUMBER INTEGER DEFAULT 0,
|
||||||
|
$MESSAGE_EXTRAS BLOB DEFAULT NULL
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -343,7 +346,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||||
SCHEDULED_DATE,
|
SCHEDULED_DATE,
|
||||||
LATEST_REVISION_ID,
|
LATEST_REVISION_ID,
|
||||||
ORIGINAL_MESSAGE_ID,
|
ORIGINAL_MESSAGE_ID,
|
||||||
REVISION_NUMBER
|
REVISION_NUMBER,
|
||||||
|
MESSAGE_EXTRAS
|
||||||
)
|
)
|
||||||
|
|
||||||
private val MMS_PROJECTION: Array<String> = MMS_PROJECTION_BASE + "NULL AS ${AttachmentTable.ATTACHMENT_JSON_ALIAS}"
|
private val MMS_PROJECTION: Array<String> = MMS_PROJECTION_BASE + "NULL AS ${AttachmentTable.ATTACHMENT_JSON_ALIAS}"
|
||||||
|
@ -4985,6 +4989,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||||
val originalMessageId: MessageId? = cursor.requireLong(ORIGINAL_MESSAGE_ID).let { if (it == 0L) null else MessageId(it) }
|
val originalMessageId: MessageId? = cursor.requireLong(ORIGINAL_MESSAGE_ID).let { if (it == 0L) null else MessageId(it) }
|
||||||
val editCount = cursor.requireInt(REVISION_NUMBER)
|
val editCount = cursor.requireInt(REVISION_NUMBER)
|
||||||
val isRead = cursor.requireBoolean(READ)
|
val isRead = cursor.requireBoolean(READ)
|
||||||
|
val messageExtraBytes = cursor.requireBlob(MESSAGE_EXTRAS)
|
||||||
|
val messageExtras = if (messageExtraBytes != null) MessageExtras.ADAPTER.decode(messageExtraBytes) else null
|
||||||
|
|
||||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||||
hasReadReceipt = false
|
hasReadReceipt = false
|
||||||
|
@ -5072,7 +5078,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||||
latestRevisionId,
|
latestRevisionId,
|
||||||
originalMessageId,
|
originalMessageId,
|
||||||
editCount,
|
editCount,
|
||||||
isRead
|
isRead,
|
||||||
|
messageExtras
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||||
|
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
||||||
import org.thoughtcrime.securesms.database.model.serialize
|
import org.thoughtcrime.securesms.database.model.serialize
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
import org.thoughtcrime.securesms.groups.BadGroupIdException
|
import org.thoughtcrime.securesms.groups.BadGroupIdException
|
||||||
|
@ -97,6 +98,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
const val SNIPPET_URI = "snippet_uri"
|
const val SNIPPET_URI = "snippet_uri"
|
||||||
const val SNIPPET_CONTENT_TYPE = "snippet_content_type"
|
const val SNIPPET_CONTENT_TYPE = "snippet_content_type"
|
||||||
const val SNIPPET_EXTRAS = "snippet_extras"
|
const val SNIPPET_EXTRAS = "snippet_extras"
|
||||||
|
const val SNIPPET_MESSAGE_EXTRAS = "snippet_message_extras"
|
||||||
const val ARCHIVED = "archived"
|
const val ARCHIVED = "archived"
|
||||||
const val STATUS = "status"
|
const val STATUS = "status"
|
||||||
const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt"
|
const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt"
|
||||||
|
@ -137,7 +139,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
$LAST_SCROLLED INTEGER DEFAULT 0,
|
$LAST_SCROLLED INTEGER DEFAULT 0,
|
||||||
$PINNED INTEGER DEFAULT 0,
|
$PINNED INTEGER DEFAULT 0,
|
||||||
$UNREAD_SELF_MENTION_COUNT INTEGER DEFAULT 0,
|
$UNREAD_SELF_MENTION_COUNT INTEGER DEFAULT 0,
|
||||||
$ACTIVE INTEGER DEFAULT 0
|
$ACTIVE INTEGER DEFAULT 0,
|
||||||
|
$SNIPPET_MESSAGE_EXTRAS BLOB DEFAULT NULL
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -164,6 +167,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
SNIPPET_URI,
|
SNIPPET_URI,
|
||||||
SNIPPET_CONTENT_TYPE,
|
SNIPPET_CONTENT_TYPE,
|
||||||
SNIPPET_EXTRAS,
|
SNIPPET_EXTRAS,
|
||||||
|
SNIPPET_MESSAGE_EXTRAS,
|
||||||
ARCHIVED,
|
ARCHIVED,
|
||||||
STATUS,
|
STATUS,
|
||||||
HAS_DELIVERY_RECEIPT,
|
HAS_DELIVERY_RECEIPT,
|
||||||
|
@ -223,7 +227,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
expiresIn: Long,
|
expiresIn: Long,
|
||||||
readReceiptCount: Int,
|
readReceiptCount: Int,
|
||||||
unreadCount: Int,
|
unreadCount: Int,
|
||||||
unreadMentionCount: Int
|
unreadMentionCount: Int,
|
||||||
|
messageExtras: MessageExtras?
|
||||||
) {
|
) {
|
||||||
var extraSerialized: String? = null
|
var extraSerialized: String? = null
|
||||||
|
|
||||||
|
@ -249,7 +254,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
EXPIRES_IN to expiresIn,
|
EXPIRES_IN to expiresIn,
|
||||||
ACTIVE to 1,
|
ACTIVE to 1,
|
||||||
UNREAD_COUNT to unreadCount,
|
UNREAD_COUNT to unreadCount,
|
||||||
UNREAD_SELF_MENTION_COUNT to unreadMentionCount
|
UNREAD_SELF_MENTION_COUNT to unreadMentionCount,
|
||||||
|
SNIPPET_MESSAGE_EXTRAS to messageExtras?.encode()
|
||||||
)
|
)
|
||||||
|
|
||||||
writableDatabase
|
writableDatabase
|
||||||
|
@ -1479,7 +1485,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
expiresIn = 0,
|
expiresIn = 0,
|
||||||
readReceiptCount = 0,
|
readReceiptCount = 0,
|
||||||
unreadCount = 0,
|
unreadCount = 0,
|
||||||
unreadMentionCount = 0
|
unreadMentionCount = 0,
|
||||||
|
messageExtras = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return@withinTransaction true
|
return@withinTransaction true
|
||||||
|
@ -1508,7 +1515,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
expiresIn = record.expiresIn,
|
expiresIn = record.expiresIn,
|
||||||
readReceiptCount = record.hasReadReceipt().toInt(),
|
readReceiptCount = record.hasReadReceipt().toInt(),
|
||||||
unreadCount = unreadCount,
|
unreadCount = unreadCount,
|
||||||
unreadMentionCount = unreadMentionCount
|
unreadMentionCount = unreadMentionCount,
|
||||||
|
messageExtras = record.messageExtras
|
||||||
)
|
)
|
||||||
|
|
||||||
if (notifyListeners) {
|
if (notifyListeners) {
|
||||||
|
@ -1667,6 +1675,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
SNIPPET_URI to null,
|
SNIPPET_URI to null,
|
||||||
SNIPPET_CONTENT_TYPE to null,
|
SNIPPET_CONTENT_TYPE to null,
|
||||||
SNIPPET_EXTRAS to null,
|
SNIPPET_EXTRAS to null,
|
||||||
|
SNIPPET_MESSAGE_EXTRAS to null,
|
||||||
UNREAD_COUNT to 0,
|
UNREAD_COUNT to 0,
|
||||||
ARCHIVED to 0,
|
ARCHIVED to 0,
|
||||||
STATUS to 0,
|
STATUS to 0,
|
||||||
|
@ -1898,6 +1907,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||||
|
|
||||||
val hasReadReceipt = TextSecurePreferences.isReadReceiptsEnabled(context) && cursor.requireBoolean(HAS_READ_RECEIPT)
|
val hasReadReceipt = TextSecurePreferences.isReadReceiptsEnabled(context) && cursor.requireBoolean(HAS_READ_RECEIPT)
|
||||||
val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS))
|
val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS))
|
||||||
|
val messageExtras = cursor.getBlob(cursor.getColumnIndexOrThrow(SNIPPET_MESSAGE_EXTRAS))
|
||||||
val extra: Extra? = if (extraString != null) {
|
val extra: Extra? = if (extraString != null) {
|
||||||
try {
|
try {
|
||||||
val jsonObject = SaneJSONObject(JSONObject(extraString))
|
val jsonObject = SaneJSONObject(JSONObject(extraString))
|
||||||
|
|
|
@ -74,6 +74,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V213_FixUsernameInE
|
||||||
import org.thoughtcrime.securesms.database.helpers.migration.V214_PhoneNumberSharingColumn
|
import org.thoughtcrime.securesms.database.helpers.migration.V214_PhoneNumberSharingColumn
|
||||||
import org.thoughtcrime.securesms.database.helpers.migration.V215_RemoveAttachmentUniqueId
|
import org.thoughtcrime.securesms.database.helpers.migration.V215_RemoveAttachmentUniqueId
|
||||||
import org.thoughtcrime.securesms.database.helpers.migration.V216_PhoneNumberDiscoverable
|
import org.thoughtcrime.securesms.database.helpers.migration.V216_PhoneNumberDiscoverable
|
||||||
|
import org.thoughtcrime.securesms.database.helpers.migration.V217_MessageTableExtrasColumn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||||
|
@ -150,10 +151,11 @@ object SignalDatabaseMigrations {
|
||||||
213 to V213_FixUsernameInE164Column,
|
213 to V213_FixUsernameInE164Column,
|
||||||
214 to V214_PhoneNumberSharingColumn,
|
214 to V214_PhoneNumberSharingColumn,
|
||||||
215 to V215_RemoveAttachmentUniqueId,
|
215 to V215_RemoveAttachmentUniqueId,
|
||||||
216 to V216_PhoneNumberDiscoverable
|
216 to V216_PhoneNumberDiscoverable,
|
||||||
|
217 to V217_MessageTableExtrasColumn
|
||||||
)
|
)
|
||||||
|
|
||||||
const val DATABASE_VERSION = 216
|
const val DATABASE_VERSION = 217
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a message_extras column to the messages table. This allows us to
|
||||||
|
* store extra data for messages in a more future proof and structured way.
|
||||||
|
*/
|
||||||
|
@Suppress("ClassName")
|
||||||
|
object V217_MessageTableExtrasColumn : SignalDatabaseMigration {
|
||||||
|
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||||
|
db.execSQL("ALTER TABLE message ADD COLUMN message_extras BLOB DEFAULT NULL")
|
||||||
|
db.execSQL("ALTER TABLE thread ADD COLUMN snippet_message_extras BLOB DEFAULT NULL")
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,17 +25,53 @@ import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemov
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
|
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
|
||||||
import org.signal.storageservice.protos.groups.local.EnabledState;
|
import org.signal.storageservice.protos.groups.local.EnabledState;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GenericGroupUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupAdminStatusUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupAnnouncementOnlyChangeUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupAttributesAccessLevelChangeUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupAvatarUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupChangeChatUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupCreationUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupDescriptionUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationAcceptedUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationDeclinedUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationRevokedUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkAdminApprovalUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkDisabledUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkEnabledUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkResetUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestApprovalUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestCanceledUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberAddedUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLeftUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberRemovedUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupMembershipAccessLevelChangeUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupNameUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupUnknownInviteeUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2AccessLevel;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationDroppedMembersUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationInvitedMembersUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationSelfInvitedUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedOtherUserToGroupUpdate;
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedToGroupUpdate;
|
||||||
|
import org.thoughtcrime.securesms.database.model.databaseprotos.GV2UpdateDescription;
|
||||||
import org.thoughtcrime.securesms.groups.GV2AccessLevelUtil;
|
import org.thoughtcrime.securesms.groups.GV2AccessLevelUtil;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||||
import org.whispersystems.signalservice.api.push.ServiceIds;
|
import org.whispersystems.signalservice.api.push.ServiceIds;
|
||||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -104,6 +140,485 @@ final class GroupsV2UpdateMessageProducer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<UpdateDescription> describeChanges(@NonNull List<GroupChangeChatUpdate.Update> groupUpdates) {
|
||||||
|
List<UpdateDescription> updates = new LinkedList<>();
|
||||||
|
for (GroupChangeChatUpdate.Update update : groupUpdates) {
|
||||||
|
describeUpdate(update, updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
return updates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeUpdate(@NonNull GroupChangeChatUpdate.Update update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.genericGroupUpdate != null) {
|
||||||
|
describeGenericGroupUpdate(update.genericGroupUpdate, updates);
|
||||||
|
} else if (update.groupCreationUpdate != null) {
|
||||||
|
describeGroupCreationUpdate(update.groupCreationUpdate, updates);
|
||||||
|
} else if (update.groupNameUpdate != null) {
|
||||||
|
describeGroupNameUpdate(update.groupNameUpdate, updates);
|
||||||
|
} else if (update.groupAvatarUpdate != null) {
|
||||||
|
describeAvatarChange(update.groupAvatarUpdate, updates);
|
||||||
|
} else if (update.groupDescriptionUpdate != null) {
|
||||||
|
describeDescriptionChange(update.groupDescriptionUpdate, updates);
|
||||||
|
} else if (update.groupMembershipAccessLevelChangeUpdate != null) {
|
||||||
|
describeGroupMembershipAccessLevelChange(update.groupMembershipAccessLevelChangeUpdate, updates);
|
||||||
|
} else if (update.groupAttributesAccessLevelChangeUpdate != null) {
|
||||||
|
describeGroupAttributesAccessLevelChange(update.groupAttributesAccessLevelChangeUpdate, updates);
|
||||||
|
} else if (update.groupAnnouncementOnlyChangeUpdate != null) {
|
||||||
|
describeGroupAnnouncementOnlyUpdate(update.groupAnnouncementOnlyChangeUpdate, updates);
|
||||||
|
} else if (update.groupAdminStatusUpdate != null) {
|
||||||
|
describeAdminStatusChange(update.groupAdminStatusUpdate, updates);
|
||||||
|
} else if (update.groupMemberLeftUpdate != null) {
|
||||||
|
describeGroupMemberLeftChange(update.groupMemberLeftUpdate, updates);
|
||||||
|
} else if (update.groupMemberRemovedUpdate != null) {
|
||||||
|
describeGroupMemberRemovedChange(update.groupMemberRemovedUpdate, updates);
|
||||||
|
} else if (update.selfInvitedToGroupUpdate != null) {
|
||||||
|
describeSelfInvitedToGroupUpdate(update.selfInvitedToGroupUpdate, updates);
|
||||||
|
} else if (update.selfInvitedOtherUserToGroupUpdate != null) {
|
||||||
|
describeSelfInvitedOtherUserToGroupUpdate(update.selfInvitedOtherUserToGroupUpdate, updates);
|
||||||
|
} else if (update.groupUnknownInviteeUpdate != null) {
|
||||||
|
describeUnknownUsersInvitedUpdate(update.groupUnknownInviteeUpdate, updates);
|
||||||
|
} else if (update.groupInvitationAcceptedUpdate != null) {
|
||||||
|
describeGroupInvitationAcceptedUpdate(update.groupInvitationAcceptedUpdate, updates);
|
||||||
|
} else if (update.groupMemberJoinedUpdate != null) {
|
||||||
|
describeGroupMemberJoinedUpdate(update.groupMemberJoinedUpdate, updates);
|
||||||
|
} else if (update.groupMemberAddedUpdate != null) {
|
||||||
|
describeGroupMemberAddedUpdate(update.groupMemberAddedUpdate, updates);
|
||||||
|
} else if (update.groupInvitationDeclinedUpdate != null) {
|
||||||
|
describeGroupInvitationDeclinedUpdate(update.groupInvitationDeclinedUpdate, updates);
|
||||||
|
} else if (update.groupInvitationRevokedUpdate != null) {
|
||||||
|
describeGroupInvitationRevokedUpdate(update.groupInvitationRevokedUpdate, updates);
|
||||||
|
} else if (update.groupJoinRequestUpdate != null) {
|
||||||
|
describeGroupJoinRequestUpdate(update.groupJoinRequestUpdate, updates);
|
||||||
|
} else if (update.groupJoinRequestApprovalUpdate != null) {
|
||||||
|
describeGroupJoinRequestApprovedUpdate(update.groupJoinRequestApprovalUpdate, updates);
|
||||||
|
} else if (update.groupJoinRequestCanceledUpdate != null) {
|
||||||
|
describeGroupJoinRequestCanceledUpdate(update.groupJoinRequestCanceledUpdate, updates);
|
||||||
|
} else if (update.groupInviteLinkResetUpdate != null) {
|
||||||
|
describeInviteLinkResetUpdate(update.groupInviteLinkResetUpdate, updates);
|
||||||
|
} else if (update.groupInviteLinkEnabledUpdate != null) {
|
||||||
|
describeInviteLinkEnabledUpdate(update.groupInviteLinkEnabledUpdate, updates);
|
||||||
|
} else if (update.groupInviteLinkDisabledUpdate != null) {
|
||||||
|
describeInviteLinkDisabledUpdate(update.groupInviteLinkDisabledUpdate, updates);
|
||||||
|
} else if (update.groupInviteLinkAdminApprovalUpdate != null) {
|
||||||
|
describeGroupInviteLinkAdminApprovalUpdate(update.groupInviteLinkAdminApprovalUpdate, updates);
|
||||||
|
} else if (update.groupV2MigrationUpdate != null) {
|
||||||
|
describeGroupV2MigrationUpdate(update.groupV2MigrationUpdate, updates);
|
||||||
|
} else if (update.groupV2MigrationDroppedMembersUpdate != null) {
|
||||||
|
describeGroupV2MigrationDroppedMembersUpdate(update.groupV2MigrationDroppedMembersUpdate, updates);
|
||||||
|
} else if (update.groupV2MigrationInvitedMembersUpdate != null) {
|
||||||
|
describeGroupV2MigrationInvitedMembersUpdate(update.groupV2MigrationInvitedMembersUpdate, updates);
|
||||||
|
} else if (update.groupV2MigrationSelfInvitedUpdate != null) {
|
||||||
|
describeGroupV2MigrationSelfInvitedUpdate(update.groupV2MigrationSelfInvitedUpdate, updates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupV2MigrationSelfInvitedUpdate(@NonNull GroupV2MigrationSelfInvitedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_couldnt_be_added_to_the_new_group_and_have_been_invited_to_join), R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupV2MigrationDroppedMembersUpdate(@NonNull GroupV2MigrationDroppedMembersUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_removed, update.droppedMembersCount, update.droppedMembersCount), R.drawable.ic_update_group_remove_16));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupV2MigrationInvitedMembersUpdate(@NonNull GroupV2MigrationInvitedMembersUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, update.invitedMembersCount, update.invitedMembersCount), R.drawable.ic_update_group_remove_16));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupV2MigrationUpdate(@NonNull GroupV2MigrationUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_this_group_was_updated_to_a_new_group), R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupInviteLinkAdminApprovalUpdate(@NonNull GroupInviteLinkAdminApprovalUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
if (update.linkRequiresAdminApproval) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_admin_approval_for_the_group_link_has_been_turned_on), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_admin_approval_for_the_group_link_has_been_turned_off), R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (selfIds.matches(update.updaterAci)) {
|
||||||
|
if (update.linkRequiresAdminApproval) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_on_admin_approval_for_the_group_link), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_off_admin_approval_for_the_group_link), R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (update.linkRequiresAdminApproval) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_admin_approval_for_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_turned_off_admin_approval_for_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeInviteLinkDisabledUpdate(@NonNull GroupInviteLinkDisabledUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||||
|
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_turned_off), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_off_the_group_link), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_turned_off_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeInviteLinkEnabledUpdate(@NonNull GroupInviteLinkEnabledUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||||
|
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
if (update.linkRequiresAdminApproval) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_turned_on_with_admin_approval_on), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_turned_on_with_admin_approval_off), R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (editorIsYou) {
|
||||||
|
if (update.linkRequiresAdminApproval) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_on_the_group_link_with_admin_approval_on), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_on_the_group_link_with_admin_approval_off), R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (update.linkRequiresAdminApproval) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_on, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_off, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeInviteLinkResetUpdate(@NonNull GroupInviteLinkResetUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_reset), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
if (selfIds.matches(update.updaterAci)) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_reset_the_group_link), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_reset_the_group_link, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupJoinRequestCanceledUpdate(@NonNull GroupJoinRequestCanceledUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
boolean requestingMemberIsYou = selfIds.matches(update.requestorAci);
|
||||||
|
|
||||||
|
if (requestingMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_canceled_your_request_to_join_the_group), R.drawable.ic_update_group_decline_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_canceled_their_request_to_join_the_group, update.requestorAci, R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupJoinRequestApprovedUpdate(@NonNull GroupJoinRequestApprovalUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
boolean requestingMemberIsYou = selfIds.matches(update.requestorAci);
|
||||||
|
|
||||||
|
if (update.wasApproved) {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
if (requestingMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_approved), R.drawable.ic_update_group_accept_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_approved, update.requestorAci, R.drawable.ic_update_group_accept_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (requestingMemberIsYou) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_approved_your_request_to_join_the_group, update.updaterAci, R.drawable.ic_update_group_accept_16));
|
||||||
|
} else {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||||
|
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_you_approved_a_request_to_join_the_group_from_s, update.requestorAci, R.drawable.ic_update_group_accept_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_approved_a_request_to_join_the_group_from_s, update.updaterAci, update.requestorAci, R.drawable.ic_update_group_accept_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
if (requestingMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_denied_by_an_admin), R.drawable.ic_update_group_decline_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_denied, update.requestorAci, R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (requestingMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_denied_by_an_admin), R.drawable.ic_update_group_decline_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_denied_a_request_to_join_the_group_from_s, update.updaterAci, update.requestorAci, R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupJoinRequestUpdate(@NonNull GroupJoinRequestUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (selfIds.matches(update.requestorAci)) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_sent_a_request_to_join_the_group), R.drawable.ic_update_group_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_requested_to_join_via_the_group_link, update.requestorAci, R.drawable.ic_update_group_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupInvitationRevokedUpdate(@NonNull GroupInvitationRevokedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
int revokedMeCount = 0;
|
||||||
|
for (GroupInvitationRevokedUpdate.Invitee invitee : update.invitees) {
|
||||||
|
if (selfIds.matches(invitee.inviteeAci) || selfIds.matches(invitee.inviteePni)) {
|
||||||
|
revokedMeCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int notMeInvitees = update.invitees.size() - revokedMeCount;
|
||||||
|
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
if (revokedMeCount > 0) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
if (notMeInvitees > 0) {
|
||||||
|
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_d_invitations_were_revoked, notMeInvitees, notMeInvitees), R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (revokedMeCount > 0) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, update.updaterAci, R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
if (selfIds.matches(update.updaterAci)) {
|
||||||
|
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_you_revoked_invites, notMeInvitees, notMeInvitees), R.drawable.ic_update_group_decline_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.plurals.MessageRecord_s_revoked_invites, notMeInvitees, update.updaterAci, notMeInvitees, R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupInvitationDeclinedUpdate(@NonNull GroupInvitationDeclinedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (selfIds.matches(update.inviteeAci)) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_declined_the_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_someone_declined_an_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupMemberAddedUpdate(@NonNull GroupMemberAddedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
boolean newMemberIsYou = selfIds.matches(update.newMemberAci);
|
||||||
|
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
if (newMemberIsYou) {
|
||||||
|
updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, update.newMemberAci, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
} else if (update.hadOpenInvitation) {
|
||||||
|
if (selfIds.matches(update.updaterAci)) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_you_added_invited_member_s, update.newMemberAci, R.drawable.ic_update_group_add_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, update.updaterAci, update.newMemberAci, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (newMemberIsYou) {
|
||||||
|
updates.add(0, updateDescription(R.string.MessageRecord_s_added_you, update.updaterAci, R.drawable.ic_update_group_add_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_added_s, update.updaterAci, update.newMemberAci, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupMemberJoinedUpdate(@NonNull GroupMemberJoinedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
boolean newMemberIsYou = selfIds.matches(update.newMemberAci);
|
||||||
|
|
||||||
|
if (newMemberIsYou) {
|
||||||
|
updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, update.newMemberAci, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupInvitationAcceptedUpdate(@NonNull GroupInvitationAcceptedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (selfIds.matches(update.newMemberAci)) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_accepted_invite), R.drawable.ic_update_group_accept_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_accepted_invite, update.newMemberAci, R.drawable.ic_update_group_accept_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeUnknownUsersInvitedUpdate(@NonNull GroupUnknownInviteeUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.inviterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_d_people_were_invited_to_the_group, update.inviteeCount, update.inviteeCount), R.drawable.ic_update_group_add_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, update.inviteeCount, update.inviterAci, update.inviteeCount, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void describeSelfInvitedOtherUserToGroupUpdate(@NonNull SelfInvitedOtherUserToGroupUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, update.inviteeServiceId, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeSelfInvitedToGroupUpdate(@NonNull SelfInvitedToGroupUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.inviterAci == null) {
|
||||||
|
updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_were_invited_to_the_group), R.drawable.ic_update_group_add_16));
|
||||||
|
} else {
|
||||||
|
updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, update.inviterAci, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGenericGroupUpdate(@NonNull GenericGroupUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_was_updated), R.drawable.ic_update_group_16));
|
||||||
|
} else {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||||
|
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_updated_group, update.updaterAci, R.drawable.ic_update_group_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupCreationUpdate(@NonNull GroupCreationUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16));
|
||||||
|
} else {
|
||||||
|
if (selfIds.matches(update.updaterAci)) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_created_the_group), R.drawable.ic_update_group_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_added_you, update.updaterAci, R.drawable.ic_update_group_add_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupNameUpdate(@NonNull GroupNameUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(update.newGroupName)), R.drawable.ic_update_group_name_16));
|
||||||
|
} else {
|
||||||
|
String newTitle = StringUtil.isolateBidi(update.newGroupName);
|
||||||
|
if (selfIds.matches(update.updaterAci)) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_name_to_s, newTitle), R.drawable.ic_update_group_name_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_name_to_s, update.updaterAci, newTitle, R.drawable.ic_update_group_name_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupMembershipAccessLevelChange(@NonNull GroupMembershipAccessLevelChangeUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.accessLevel == GroupV2AccessLevel.UNKNOWN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String accessLevel = GV2AccessLevelUtil.toString(context, backupGv2AccessLevelToGroups(update.accessLevel));
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_membership_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||||
|
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_membership_to_s, accessLevel), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_membership_to_s, update.updaterAci, accessLevel, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupAttributesAccessLevelChange(@NonNull GroupAttributesAccessLevelChangeUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.accessLevel == GroupV2AccessLevel.UNKNOWN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String accessLevel = GV2AccessLevelUtil.toString(context, backupGv2AccessLevelToGroups(update.accessLevel));
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_info_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||||
|
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_info_to_s, accessLevel), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_info_to_s, update.updaterAci, accessLevel, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupAnnouncementOnlyUpdate(@NonNull GroupAnnouncementOnlyChangeUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.updaterAci == null) {
|
||||||
|
if (update.isAnnouncementOnly) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_only_admins_to_send), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_all_members_to_send), R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||||
|
|
||||||
|
if (update.isAnnouncementOnly) {
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_only_admins_to_send), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_allow_only_admins_to_send, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_all_members_to_send), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_allow_all_members_to_send, update.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupMemberLeftChange(@NonNull GroupMemberLeftUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.aci == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean editorIsYou = selfIds.matches(update.aci);
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_left_the_group), R.drawable.ic_update_group_leave_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_left_the_group, update.aci, R.drawable.ic_update_group_leave_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void describeGroupMemberRemovedChange(@NonNull GroupMemberRemovedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (update.removerAci == null) {
|
||||||
|
boolean removedMemberIsYou = selfIds.matches(update.removedAci);
|
||||||
|
|
||||||
|
if (removedMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_no_longer_in_the_group), R.drawable.ic_update_group_leave_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_in_the_group, update.removedAci, R.drawable.ic_update_group_leave_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
boolean editorIsYou = selfIds.matches(update.removerAci);
|
||||||
|
|
||||||
|
boolean removedMemberIsYou = selfIds.matches(update.removedAci);
|
||||||
|
|
||||||
|
if (editorIsYou) {
|
||||||
|
if (removedMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_left_the_group), R.drawable.ic_update_group_leave_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_you_removed_s, update.removedAci, R.drawable.ic_update_group_remove_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (removedMemberIsYou) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_removed_you_from_the_group, update.removerAci, R.drawable.ic_update_group_remove_16));
|
||||||
|
} else {
|
||||||
|
if (update.removerAci.equals(update.removedAci)) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_left_the_group, update.removedAci, R.drawable.ic_update_group_leave_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_removed_s, update.removerAci, update.removedAci, R.drawable.ic_update_group_remove_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AccessControl.AccessRequired backupGv2AccessLevelToGroups(@NonNull GroupV2AccessLevel accessLevel) {
|
||||||
|
switch (accessLevel) {
|
||||||
|
case ANY: return AccessControl.AccessRequired.ANY;
|
||||||
|
case MEMBER: return AccessControl.AccessRequired.MEMBER;
|
||||||
|
case ADMINISTRATOR: return AccessControl.AccessRequired.ADMINISTRATOR;
|
||||||
|
case UNSATISFIABLE: return AccessControl.AccessRequired.UNSATISFIABLE;
|
||||||
|
default:
|
||||||
|
case UNKNOWN: return AccessControl.AccessRequired.UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<UpdateDescription> describeChanges(@Nullable DecryptedGroup previousGroupState, @NonNull DecryptedGroupChange change) {
|
List<UpdateDescription> describeChanges(@Nullable DecryptedGroup previousGroupState, @NonNull DecryptedGroupChange change) {
|
||||||
if (new DecryptedGroup().equals(previousGroupState)) {
|
if (new DecryptedGroup().equals(previousGroupState)) {
|
||||||
previousGroupState = null;
|
previousGroupState = null;
|
||||||
|
@ -317,6 +832,51 @@ final class GroupsV2UpdateMessageProducer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void describeAdminStatusChange(@NonNull GroupAdminStatusUpdate groupAdminStatusUpdate, List<UpdateDescription> updates) {
|
||||||
|
boolean changedMemberIsYou = selfIds.matches(groupAdminStatusUpdate.memberAci);
|
||||||
|
|
||||||
|
if (groupAdminStatusUpdate.updaterAci != null) {
|
||||||
|
boolean editorIsYou = selfIds.matches(groupAdminStatusUpdate.updaterAci);
|
||||||
|
|
||||||
|
if (groupAdminStatusUpdate.wasAdminStatusGranted) {
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_you_made_s_an_admin, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
if (changedMemberIsYou) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_made_you_an_admin, groupAdminStatusUpdate.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_made_s_an_admin, groupAdminStatusUpdate.updaterAci, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_you_revoked_admin_privileges_from_s, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
if (changedMemberIsYou) {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_admin_privileges, groupAdminStatusUpdate.updaterAci, R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_revoked_admin_privileges_from_s, groupAdminStatusUpdate.updaterAci, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (groupAdminStatusUpdate.wasAdminStatusGranted) {
|
||||||
|
if (changedMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_now_an_admin), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_is_now_an_admin, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (changedMemberIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_no_longer_an_admin), R.drawable.ic_update_group_role_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_an_admin, groupAdminStatusUpdate.memberAci, R.drawable.ic_update_group_role_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void describeInvitations(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
private void describeInvitations(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
||||||
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
|
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
|
||||||
int notYouInviteCount = 0;
|
int notYouInviteCount = 0;
|
||||||
|
@ -481,6 +1041,20 @@ final class GroupsV2UpdateMessageProducer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void describeDescriptionChange(@NonNull GroupDescriptionUpdate groupDescriptionUpdate, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (groupDescriptionUpdate.updaterAci != null) {
|
||||||
|
boolean editorIsYou = selfIds.matches(groupDescriptionUpdate.updaterAci);
|
||||||
|
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_description), R.drawable.ic_update_group_name_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_description, groupDescriptionUpdate.updaterAci, R.drawable.ic_update_group_name_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(groupDescriptionUpdate.newDescription)), R.drawable.ic_update_group_name_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void describeUnknownEditorNewDescription(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
private void describeUnknownEditorNewDescription(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
||||||
if (change.newDescription != null) {
|
if (change.newDescription != null) {
|
||||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_description_has_changed), R.drawable.ic_update_group_name_16));
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_description_has_changed), R.drawable.ic_update_group_name_16));
|
||||||
|
@ -499,6 +1073,20 @@ final class GroupsV2UpdateMessageProducer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void describeAvatarChange(@NonNull GroupAvatarUpdate groupAvatarUpdate, @NonNull List<UpdateDescription> updates) {
|
||||||
|
if (groupAvatarUpdate.updaterAci != null) {
|
||||||
|
boolean editorIsYou = selfIds.matches(groupAvatarUpdate.updaterAci);
|
||||||
|
|
||||||
|
if (editorIsYou) {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_avatar), R.drawable.ic_update_group_avatar_16));
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_avatar, groupAvatarUpdate.updaterAci, R.drawable.ic_update_group_avatar_16));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_group_avatar_has_been_changed), R.drawable.ic_update_group_avatar_16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void describeUnknownEditorNewAvatar(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
private void describeUnknownEditorNewAvatar(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
||||||
if (change.newAvatar != null) {
|
if (change.newAvatar != null) {
|
||||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_group_avatar_has_been_changed), R.drawable.ic_update_group_avatar_16));
|
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_group_avatar_has_been_changed), R.drawable.ic_update_group_avatar_16));
|
||||||
|
|
|
@ -56,7 +56,8 @@ public class InMemoryMessageRecord extends MessageRecord {
|
||||||
false,
|
false,
|
||||||
-1,
|
-1,
|
||||||
null,
|
null,
|
||||||
0);
|
0,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
|
||||||
|
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchoverEvent;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchoverEvent;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent;
|
||||||
|
@ -104,6 +105,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||||
private final long receiptTimestamp;
|
private final long receiptTimestamp;
|
||||||
private final MessageId originalMessageId;
|
private final MessageId originalMessageId;
|
||||||
private final int revisionNumber;
|
private final int revisionNumber;
|
||||||
|
private final MessageExtras messageExtras;
|
||||||
|
|
||||||
protected Boolean isJumboji = null;
|
protected Boolean isJumboji = null;
|
||||||
|
|
||||||
|
@ -123,7 +125,8 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||||
boolean viewed,
|
boolean viewed,
|
||||||
long receiptTimestamp,
|
long receiptTimestamp,
|
||||||
@Nullable MessageId originalMessageId,
|
@Nullable MessageId originalMessageId,
|
||||||
int revisionNumber)
|
int revisionNumber,
|
||||||
|
@Nullable MessageExtras messageExtras)
|
||||||
{
|
{
|
||||||
super(body, fromRecipient, toRecipient, dateSent, dateReceived,
|
super(body, fromRecipient, toRecipient, dateSent, dateReceived,
|
||||||
threadId, deliveryStatus, hasDeliveryReceipt, type,
|
threadId, deliveryStatus, hasDeliveryReceipt, type,
|
||||||
|
@ -143,6 +146,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||||
this.receiptTimestamp = receiptTimestamp;
|
this.receiptTimestamp = receiptTimestamp;
|
||||||
this.originalMessageId = originalMessageId;
|
this.originalMessageId = originalMessageId;
|
||||||
this.revisionNumber = revisionNumber;
|
this.revisionNumber = revisionNumber;
|
||||||
|
this.messageExtras = messageExtras;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean isMms();
|
public abstract boolean isMms();
|
||||||
|
@ -287,6 +291,10 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||||
return selfCreatedGroup(change);
|
return selfCreatedGroup(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable public MessageExtras getMessageExtras() {
|
||||||
|
return messageExtras;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@Nullable DecryptedGroupV2Context getDecryptedGroupV2Context() {
|
@Nullable DecryptedGroupV2Context getDecryptedGroupV2Context() {
|
||||||
if (!isGroupUpdate() || !isGroupV2()) {
|
if (!isGroupUpdate() || !isGroupV2()) {
|
||||||
|
@ -315,6 +323,30 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||||
try {
|
try {
|
||||||
byte[] decoded = Base64.decode(body);
|
byte[] decoded = Base64.decode(body);
|
||||||
DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded);
|
DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded);
|
||||||
|
return getGv2ChangeDescription(context, decryptedGroupV2Context, recipientClickHandler);
|
||||||
|
} catch (IOException | IllegalArgumentException | IllegalStateException e) {
|
||||||
|
Log.w(TAG, "GV2 Message update detail could not be read", e);
|
||||||
|
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull MessageExtras messageExtras, @Nullable Consumer<RecipientId> recipientClickHandler) {
|
||||||
|
if (messageExtras.gv2UpdateDescription != null) {
|
||||||
|
if (messageExtras.gv2UpdateDescription.groupChangeUpdate != null) {
|
||||||
|
GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, SignalStore.account().getServiceIds(), recipientClickHandler);
|
||||||
|
|
||||||
|
return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(messageExtras.gv2UpdateDescription.groupChangeUpdate.updates));
|
||||||
|
} else if (messageExtras.gv2UpdateDescription.gv2ChangeDescription != null) {
|
||||||
|
return getGv2ChangeDescription(context, messageExtras.gv2UpdateDescription.gv2ChangeDescription, recipientClickHandler);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "GV2 Update Description missing group change update!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull DecryptedGroupV2Context decryptedGroupV2Context, @Nullable Consumer<RecipientId> recipientClickHandler) {
|
||||||
|
try {
|
||||||
GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, SignalStore.account().getServiceIds(), recipientClickHandler);
|
GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, SignalStore.account().getServiceIds(), recipientClickHandler);
|
||||||
|
|
||||||
if (decryptedGroupV2Context.change != null && ((decryptedGroupV2Context.groupState != null && decryptedGroupV2Context.groupState.revision != 0) || decryptedGroupV2Context.previousGroupState != null)) {
|
if (decryptedGroupV2Context.change != null && ((decryptedGroupV2Context.groupState != null && decryptedGroupV2Context.groupState.revision != 0) || decryptedGroupV2Context.previousGroupState != null)) {
|
||||||
|
@ -332,7 +364,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||||
}
|
}
|
||||||
return UpdateDescription.concatWithNewLines(newGroupDescriptions);
|
return UpdateDescription.concatWithNewLines(newGroupDescriptions);
|
||||||
}
|
}
|
||||||
} catch (IOException | IllegalArgumentException | IllegalStateException e) {
|
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||||
Log.w(TAG, "GV2 Message update detail could not be read", e);
|
Log.w(TAG, "GV2 Message update detail could not be read", e);
|
||||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
|
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge;
|
||||||
|
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
|
@ -111,12 +112,13 @@ public class MmsMessageRecord extends MessageRecord {
|
||||||
@Nullable MessageId latestRevisionId,
|
@Nullable MessageId latestRevisionId,
|
||||||
@Nullable MessageId originalMessageId,
|
@Nullable MessageId originalMessageId,
|
||||||
int revisionNumber,
|
int revisionNumber,
|
||||||
boolean isRead)
|
boolean isRead,
|
||||||
|
@Nullable MessageExtras messageExtras)
|
||||||
{
|
{
|
||||||
super(id, body, fromRecipient, fromDeviceId, toRecipient,
|
super(id, body, fromRecipient, fromDeviceId, toRecipient,
|
||||||
dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, hasDeliveryReceipt,
|
dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, hasDeliveryReceipt,
|
||||||
mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, hasReadReceipt,
|
mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, hasReadReceipt,
|
||||||
unidentified, reactions, remoteDelete, notifiedTimestamp, viewed, receiptTimestamp, originalMessageId, revisionNumber);
|
unidentified, reactions, remoteDelete, notifiedTimestamp, viewed, receiptTimestamp, originalMessageId, revisionNumber, messageExtras);
|
||||||
|
|
||||||
this.slideDeck = slideDeck;
|
this.slideDeck = slideDeck;
|
||||||
this.quote = quote;
|
this.quote = quote;
|
||||||
|
@ -299,7 +301,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||||
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf,
|
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf,
|
||||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||||
getOriginalMessageId(), getRevisionNumber(), isRead());
|
getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras());
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull MmsMessageRecord withoutQuote() {
|
public @NonNull MmsMessageRecord withoutQuote() {
|
||||||
|
@ -307,7 +309,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||||
hasReadReceipt(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
hasReadReceipt(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||||
getOriginalMessageId(), getRevisionNumber(), isRead());
|
getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras());
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull MmsMessageRecord withAttachments(@NonNull List<DatabaseAttachment> attachments) {
|
public @NonNull MmsMessageRecord withAttachments(@NonNull List<DatabaseAttachment> attachments) {
|
||||||
|
@ -329,7 +331,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||||
hasReadReceipt(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
hasReadReceipt(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||||
getOriginalMessageId(), getRevisionNumber(), isRead());
|
getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras());
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull MmsMessageRecord withPayment(@NonNull Payment payment) {
|
public @NonNull MmsMessageRecord withPayment(@NonNull Payment payment) {
|
||||||
|
@ -337,7 +339,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||||
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate(), getLatestRevisionId(),
|
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate(), getLatestRevisionId(),
|
||||||
getOriginalMessageId(), getRevisionNumber(), isRead());
|
getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -346,7 +348,7 @@ public class MmsMessageRecord extends MessageRecord {
|
||||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||||
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||||
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate(), getLatestRevisionId(),
|
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate(), getLatestRevisionId(),
|
||||||
getOriginalMessageId(), getRevisionNumber(), isRead());
|
getOriginalMessageId(), getRevisionNumber(), isRead(), getMessageExtras());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull List<Contact> updateContacts(@NonNull List<Contact> contacts, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
|
private static @NonNull List<Contact> updateContacts(@NonNull List<Contact> contacts, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.database.MessageTypes;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable.Extra;
|
import org.thoughtcrime.securesms.database.ThreadTable.Extra;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||||
|
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.whispersystems.signalservice.api.util.Preconditions;
|
import org.whispersystems.signalservice.api.util.Preconditions;
|
||||||
|
@ -57,6 +58,7 @@ public final class ThreadRecord {
|
||||||
private final long lastSeen;
|
private final long lastSeen;
|
||||||
private final boolean isPinned;
|
private final boolean isPinned;
|
||||||
private final int unreadSelfMentionsCount;
|
private final int unreadSelfMentionsCount;
|
||||||
|
private final MessageExtras messageExtras;
|
||||||
|
|
||||||
private ThreadRecord(@NonNull Builder builder) {
|
private ThreadRecord(@NonNull Builder builder) {
|
||||||
this.threadId = builder.threadId;
|
this.threadId = builder.threadId;
|
||||||
|
@ -79,6 +81,7 @@ public final class ThreadRecord {
|
||||||
this.lastSeen = builder.lastSeen;
|
this.lastSeen = builder.lastSeen;
|
||||||
this.isPinned = builder.isPinned;
|
this.isPinned = builder.isPinned;
|
||||||
this.unreadSelfMentionsCount = builder.unreadSelfMentionsCount;
|
this.unreadSelfMentionsCount = builder.unreadSelfMentionsCount;
|
||||||
|
this.messageExtras = builder.messageExtras;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getThreadId() {
|
public long getThreadId() {
|
||||||
|
@ -189,6 +192,10 @@ public final class ThreadRecord {
|
||||||
return extra != null && extra.isScheduled();
|
return extra != null && extra.isScheduled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable MessageExtras getMessageExtras() {
|
||||||
|
return messageExtras;
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable RecipientId getGroupAddedBy() {
|
public @Nullable RecipientId getGroupAddedBy() {
|
||||||
if (extra != null && extra.getGroupAddedBy() != null) return RecipientId.from(extra.getGroupAddedBy());
|
if (extra != null && extra.getGroupAddedBy() != null) return RecipientId.from(extra.getGroupAddedBy());
|
||||||
else return null;
|
else return null;
|
||||||
|
@ -307,6 +314,7 @@ public final class ThreadRecord {
|
||||||
private long lastSeen;
|
private long lastSeen;
|
||||||
private boolean isPinned;
|
private boolean isPinned;
|
||||||
private int unreadSelfMentionsCount;
|
private int unreadSelfMentionsCount;
|
||||||
|
private MessageExtras messageExtras;
|
||||||
|
|
||||||
public Builder(long threadId) {
|
public Builder(long threadId) {
|
||||||
this.threadId = threadId;
|
this.threadId = threadId;
|
||||||
|
@ -407,6 +415,11 @@ public final class ThreadRecord {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setSnippetMessageExtras(@Nullable MessageExtras messageExtras) {
|
||||||
|
this.messageExtras = messageExtras;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder setUnreadSelfMentionsCount(int unreadSelfMentionsCount) {
|
public Builder setUnreadSelfMentionsCount(int unreadSelfMentionsCount) {
|
||||||
this.unreadSelfMentionsCount = unreadSelfMentionsCount;
|
this.unreadSelfMentionsCount = unreadSelfMentionsCount;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -7,7 +7,6 @@ option java_package = "org.thoughtcrime.securesms.backup.v2.proto";
|
||||||
message BackupInfo {
|
message BackupInfo {
|
||||||
uint64 version = 1;
|
uint64 version = 1;
|
||||||
uint64 backupTimeMs = 2;
|
uint64 backupTimeMs = 2;
|
||||||
bytes iv = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Frame {
|
message Frame {
|
||||||
|
@ -207,6 +206,9 @@ message ChatItem {
|
||||||
repeated SendStatus sendStatus = 1;
|
repeated SendStatus sendStatus = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message DirectionlessMessageDetails {
|
||||||
|
}
|
||||||
|
|
||||||
uint64 chatId = 1; // conversation id
|
uint64 chatId = 1; // conversation id
|
||||||
uint64 authorId = 2; // recipient id
|
uint64 authorId = 2; // recipient id
|
||||||
uint64 dateSent = 3;
|
uint64 dateSent = 3;
|
||||||
|
@ -217,8 +219,9 @@ message ChatItem {
|
||||||
bool sms = 8;
|
bool sms = 8;
|
||||||
|
|
||||||
oneof directionalDetails {
|
oneof directionalDetails {
|
||||||
IncomingMessageDetails incoming = 10;
|
IncomingMessageDetails incoming = 9;
|
||||||
OutgoingMessageDetails outgoing = 12;
|
OutgoingMessageDetails outgoing = 10;
|
||||||
|
DirectionlessMessageDetails directionless = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
oneof item {
|
oneof item {
|
||||||
|
@ -415,16 +418,17 @@ message FilePointer {
|
||||||
|
|
||||||
optional bytes key = 5;
|
optional bytes key = 5;
|
||||||
optional string contentType = 6;
|
optional string contentType = 6;
|
||||||
|
// Size of fullsize decrypted media blob in bytes.
|
||||||
|
// Can be ignored if unset/unavailable.
|
||||||
optional uint32 size = 7;
|
optional uint32 size = 7;
|
||||||
optional bytes digest = 8;
|
optional bytes incrementalMac = 8;
|
||||||
optional bytes incrementalMac = 9;
|
optional bytes incrementalMacChunkSize = 9;
|
||||||
optional bytes incrementalMacChunkSize = 10;
|
optional string fileName = 10;
|
||||||
optional string fileName = 11;
|
optional uint32 flags = 11;
|
||||||
optional uint32 flags = 12;
|
optional uint32 width = 12;
|
||||||
optional uint32 width = 13;
|
optional uint32 height = 13;
|
||||||
optional uint32 height = 14;
|
optional string caption = 14;
|
||||||
optional string caption = 15;
|
optional string blurHash = 15;
|
||||||
optional string blurHash = 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Quote {
|
message Quote {
|
||||||
|
@ -478,7 +482,7 @@ message Reaction {
|
||||||
message ChatUpdateMessage {
|
message ChatUpdateMessage {
|
||||||
oneof update {
|
oneof update {
|
||||||
SimpleChatUpdate simpleUpdate = 1;
|
SimpleChatUpdate simpleUpdate = 1;
|
||||||
GroupDescriptionChatUpdate groupDescription = 2;
|
GroupChangeChatUpdate groupChange = 2;
|
||||||
ExpirationTimerChatUpdate expirationTimerChange = 3;
|
ExpirationTimerChatUpdate expirationTimerChange = 3;
|
||||||
ProfileChangeChatUpdate profileChange = 4;
|
ProfileChangeChatUpdate profileChange = 4;
|
||||||
ThreadMergeChatUpdate threadMerge = 5;
|
ThreadMergeChatUpdate threadMerge = 5;
|
||||||
|
@ -533,10 +537,6 @@ message SimpleChatUpdate {
|
||||||
Type type = 1;
|
Type type = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GroupDescriptionChatUpdate {
|
|
||||||
string newDescription = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ExpirationTimerChatUpdate {
|
message ExpirationTimerChatUpdate {
|
||||||
uint32 expiresInMs = 1;
|
uint32 expiresInMs = 1;
|
||||||
}
|
}
|
||||||
|
@ -554,6 +554,246 @@ message SessionSwitchoverChatUpdate {
|
||||||
uint64 e164 = 1;
|
uint64 e164 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GroupChangeChatUpdate {
|
||||||
|
message Update {
|
||||||
|
// Note: group expiration timer changes are represented as ExpirationTimerChatUpdate.
|
||||||
|
oneof update {
|
||||||
|
GenericGroupUpdate genericGroupUpdate = 1;
|
||||||
|
GroupCreationUpdate groupCreationUpdate = 2;
|
||||||
|
GroupNameUpdate groupNameUpdate = 3;
|
||||||
|
GroupAvatarUpdate groupAvatarUpdate = 4;
|
||||||
|
GroupDescriptionUpdate groupDescriptionUpdate = 5;
|
||||||
|
GroupMembershipAccessLevelChangeUpdate groupMembershipAccessLevelChangeUpdate = 6;
|
||||||
|
GroupAttributesAccessLevelChangeUpdate groupAttributesAccessLevelChangeUpdate = 7;
|
||||||
|
GroupAnnouncementOnlyChangeUpdate groupAnnouncementOnlyChangeUpdate = 8;
|
||||||
|
GroupAdminStatusUpdate groupAdminStatusUpdate = 9;
|
||||||
|
GroupMemberLeftUpdate groupMemberLeftUpdate = 10;
|
||||||
|
GroupMemberRemovedUpdate groupMemberRemovedUpdate = 11;
|
||||||
|
SelfInvitedToGroupUpdate selfInvitedToGroupUpdate = 12;
|
||||||
|
SelfInvitedOtherUserToGroupUpdate selfInvitedOtherUserToGroupUpdate = 13;
|
||||||
|
GroupUnknownInviteeUpdate groupUnknownInviteeUpdate = 14;
|
||||||
|
GroupInvitationAcceptedUpdate groupInvitationAcceptedUpdate = 15;
|
||||||
|
GroupInvitationDeclinedUpdate groupInvitationDeclinedUpdate = 16;
|
||||||
|
GroupMemberJoinedUpdate groupMemberJoinedUpdate = 17;
|
||||||
|
GroupMemberAddedUpdate groupMemberAddedUpdate = 18;
|
||||||
|
GroupSelfInvitationRevokedUpdate groupSelfInvitationRevokedUpdate = 19;
|
||||||
|
GroupInvitationRevokedUpdate groupInvitationRevokedUpdate = 20;
|
||||||
|
GroupJoinRequestUpdate groupJoinRequestUpdate = 21;
|
||||||
|
GroupJoinRequestApprovalUpdate groupJoinRequestApprovalUpdate = 22;
|
||||||
|
GroupJoinRequestCanceledUpdate groupJoinRequestCanceledUpdate = 23;
|
||||||
|
GroupInviteLinkResetUpdate groupInviteLinkResetUpdate = 24;
|
||||||
|
GroupInviteLinkEnabledUpdate groupInviteLinkEnabledUpdate = 25;
|
||||||
|
GroupInviteLinkAdminApprovalUpdate groupInviteLinkAdminApprovalUpdate = 26;
|
||||||
|
GroupInviteLinkDisabledUpdate groupInviteLinkDisabledUpdate = 27;
|
||||||
|
GroupMemberJoinedByLinkUpdate groupMemberJoinedByLinkUpdate = 28;
|
||||||
|
GroupV2MigrationUpdate groupV2MigrationUpdate = 29;
|
||||||
|
GroupV2MigrationSelfInvitedUpdate groupV2MigrationSelfInvitedUpdate = 30;
|
||||||
|
GroupV2MigrationInvitedMembersUpdate groupV2MigrationInvitedMembersUpdate = 31;
|
||||||
|
GroupV2MigrationDroppedMembersUpdate groupV2MigrationDroppedMembersUpdate = 32;
|
||||||
|
GroupSequenceOfRequestsAndCancelsUpdate groupSequenceOfRequestsAndCancelsUpdate = 33;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be one or more; all updates batched together came from
|
||||||
|
// a single batched group state update.
|
||||||
|
repeated Update updates = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GenericGroupUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupCreationUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupNameUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
// Null value means the group name was removed.
|
||||||
|
optional string newGroupName = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupAvatarUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
bool wasRemoved = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupDescriptionUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
// Null value means the group description was removed.
|
||||||
|
optional string newDescription = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GroupV2AccessLevel {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
ANY = 1;
|
||||||
|
MEMBER = 2;
|
||||||
|
ADMINISTRATOR = 3;
|
||||||
|
UNSATISFIABLE = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupMembershipAccessLevelChangeUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
GroupV2AccessLevel accessLevel = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupAttributesAccessLevelChangeUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
GroupV2AccessLevel accessLevel = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupAnnouncementOnlyChangeUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
bool isAnnouncementOnly = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupAdminStatusUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
// The aci who had admin status granted or revoked.
|
||||||
|
bytes memberAci = 2;
|
||||||
|
bool wasAdminStatusGranted = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupMemberLeftUpdate {
|
||||||
|
optional bytes aci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupMemberRemovedUpdate {
|
||||||
|
optional bytes removerAci = 1;
|
||||||
|
bytes removedAci = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SelfInvitedToGroupUpdate {
|
||||||
|
optional bytes inviterAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SelfInvitedOtherUserToGroupUpdate {
|
||||||
|
// If no invitee id available, use GroupUnknownInviteeUpdate
|
||||||
|
bytes inviteeServiceId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupUnknownInviteeUpdate {
|
||||||
|
// Can be the self user.
|
||||||
|
optional bytes inviterAci = 1;
|
||||||
|
uint32 inviteeCount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupInvitationAcceptedUpdate {
|
||||||
|
optional bytes inviterAci = 1;
|
||||||
|
bytes newMemberAci = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupInvitationDeclinedUpdate {
|
||||||
|
optional bytes inviterAci = 1;
|
||||||
|
// Note: if invited by pni, just set inviteeAci to nil.
|
||||||
|
optional bytes inviteeAci = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupMemberJoinedUpdate {
|
||||||
|
bytes newMemberAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupMemberAddedUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
bytes newMemberAci = 2;
|
||||||
|
bool hadOpenInvitation = 3;
|
||||||
|
// If hadOpenInvitation is true, optionally include aci of the inviter.
|
||||||
|
optional bytes inviterAci = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An invitation to self was revoked.
|
||||||
|
message GroupSelfInvitationRevokedUpdate {
|
||||||
|
optional bytes revokerAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These invitees should never be the local user.
|
||||||
|
// Use GroupSelfInvitationRevokedUpdate in those cases.
|
||||||
|
// The inviter or updater can be the local user.
|
||||||
|
message GroupInvitationRevokedUpdate {
|
||||||
|
message Invitee {
|
||||||
|
optional bytes inviterAci = 1;
|
||||||
|
// Prefer to use aci over pni. No need to set
|
||||||
|
// pni if aci is set. Both can be missing.
|
||||||
|
optional bytes inviteeAci = 2;
|
||||||
|
optional bytes inviteePni = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The member that revoked the invite(s), not the inviter!
|
||||||
|
// Assumed to be an admin (at the time, may no longer be an
|
||||||
|
// admin or even a member).
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
repeated Invitee invitees = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupJoinRequestUpdate {
|
||||||
|
bytes requestorAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupJoinRequestApprovalUpdate {
|
||||||
|
bytes requestorAci = 1;
|
||||||
|
// The aci that approved or rejected the request.
|
||||||
|
optional bytes updaterAci = 2;
|
||||||
|
bool wasApproved = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupJoinRequestCanceledUpdate {
|
||||||
|
bytes requestorAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A single requestor has requested to join and cancelled
|
||||||
|
// their request repeatedly with no other updates in between.
|
||||||
|
// The last action encompassed by this update is always a
|
||||||
|
// cancellation; if there was another open request immediately
|
||||||
|
// after, it will be a separate GroupJoinRequestUpdate, either
|
||||||
|
// in the same frame or in a subsequent frame.
|
||||||
|
message GroupSequenceOfRequestsAndCancelsUpdate {
|
||||||
|
bytes requestorAci = 1;
|
||||||
|
uint32 count = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupInviteLinkResetUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupInviteLinkEnabledUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
bool linkRequiresAdminApproval = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupInviteLinkAdminApprovalUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
bool linkRequiresAdminApproval = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupInviteLinkDisabledUpdate {
|
||||||
|
optional bytes updaterAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GroupMemberJoinedByLinkUpdate {
|
||||||
|
bytes newMemberAci = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A gv1->gv2 migration occurred.
|
||||||
|
message GroupV2MigrationUpdate {}
|
||||||
|
|
||||||
|
// Another user migrated gv1->gv2 but was unable to add
|
||||||
|
// the local user and invited them instead.
|
||||||
|
message GroupV2MigrationSelfInvitedUpdate {}
|
||||||
|
|
||||||
|
// The local user migrated gv1->gv2 but was unable to
|
||||||
|
// add some members and invited them instead.
|
||||||
|
// (Happens if we don't have the invitee's profile key)
|
||||||
|
message GroupV2MigrationInvitedMembersUpdate {
|
||||||
|
int32 invitedMembersCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The local user migrated gv1->gv2 but was unable to
|
||||||
|
// add or invite some members and dropped them instead.
|
||||||
|
// (Happens for e164 members where we don't have an aci).
|
||||||
|
message GroupV2MigrationDroppedMembersUpdate {
|
||||||
|
int32 droppedMembersCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message StickerPack {
|
message StickerPack {
|
||||||
bytes id = 1;
|
bytes id = 1;
|
||||||
bytes key = 2;
|
bytes key = 2;
|
||||||
|
|
|
@ -11,6 +11,8 @@ package signal;
|
||||||
option java_package = "org.thoughtcrime.securesms.database.model.databaseprotos";
|
option java_package = "org.thoughtcrime.securesms.database.model.databaseprotos";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import Backup.proto;
|
||||||
|
|
||||||
// DEPRECATED -- only here for database migrations
|
// DEPRECATED -- only here for database migrations
|
||||||
message ReactionList {
|
message ReactionList {
|
||||||
option deprecated = true;
|
option deprecated = true;
|
||||||
|
@ -371,3 +373,12 @@ message ExternalLaunchTransactionState {
|
||||||
GatewayRequest gatewayRequest = 2;
|
GatewayRequest gatewayRequest = 2;
|
||||||
string paymentSourceType = 3;
|
string paymentSourceType = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message MessageExtras {
|
||||||
|
GV2UpdateDescription gv2UpdateDescription = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GV2UpdateDescription {
|
||||||
|
optional DecryptedGroupV2Context gv2ChangeDescription = 1;
|
||||||
|
backup.GroupChangeChatUpdate groupChangeUpdate = 2;
|
||||||
|
}
|
|
@ -183,7 +183,8 @@ object FakeMessageRecords {
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue