mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 01:40:07 +01:00
Convert and store new group changes in MessageExtras.
This commit is contained in:
@@ -2305,6 +2305,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val parentStoryId = ParentStoryId.deserialize(cursor.requireLong(PARENT_STORY_ID))
|
||||
val messageRangesData = cursor.requireBlob(MESSAGE_RANGES)
|
||||
val scheduledDate = cursor.requireLong(SCHEDULED_DATE)
|
||||
val messageExtrasBytes = cursor.requireBlob(MESSAGE_EXTRAS)
|
||||
val messageExtras = if (messageExtrasBytes != null) MessageExtras.ADAPTER.decode(messageExtrasBytes) else null
|
||||
|
||||
val quoteId = cursor.requireLong(QUOTE_ID)
|
||||
val quoteAuthor = cursor.requireLong(QUOTE_AUTHOR)
|
||||
@@ -2357,7 +2359,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
if (body != null && (MessageTypes.isGroupQuit(outboxType) || MessageTypes.isGroupUpdate(outboxType))) {
|
||||
OutgoingMessage.groupUpdateMessage(
|
||||
threadRecipient = threadRecipient,
|
||||
groupContext = MessageGroupContext(body, MessageTypes.isGroupV2(outboxType)),
|
||||
groupContext = if (messageExtras != null) MessageGroupContext(messageExtras, MessageTypes.isGroupV2(outboxType)) else MessageGroupContext(body, MessageTypes.isGroupV2(outboxType)),
|
||||
avatar = attachments,
|
||||
sentTimeMillis = timestamp,
|
||||
expiresIn = 0,
|
||||
@@ -2859,6 +2861,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
contentValues.put(PARENT_STORY_ID, if (message.parentStoryId != null) message.parentStoryId.serialize() else 0)
|
||||
contentValues.put(SCHEDULED_DATE, message.scheduledDate)
|
||||
contentValues.putNull(LATEST_REVISION_ID)
|
||||
contentValues.put(MESSAGE_EXTRAS, message.messageExtras?.encode())
|
||||
|
||||
if (editedMessage != null) {
|
||||
contentValues.put(ORIGINAL_MESSAGE_ID, editedMessage.getOriginalOrOwnMessageId().id)
|
||||
@@ -5062,7 +5065,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val editCount = cursor.requireInt(REVISION_NUMBER)
|
||||
val isRead = cursor.requireBoolean(READ)
|
||||
val messageExtraBytes = cursor.requireBlob(MESSAGE_EXTRAS)
|
||||
val messageExtras = if (messageExtraBytes != null) MessageExtras.ADAPTER.decode(messageExtraBytes) else null
|
||||
val messageExtras = messageExtraBytes?.let { MessageExtras.ADAPTER.decode(it) }
|
||||
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
hasReadReceipt = false
|
||||
|
||||
@@ -1929,7 +1929,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
|
||||
val hasReadReceipt = TextSecurePreferences.isReadReceiptsEnabled(context) && cursor.requireBoolean(HAS_READ_RECEIPT)
|
||||
val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS))
|
||||
val messageExtras = cursor.getBlob(cursor.getColumnIndexOrThrow(SNIPPET_MESSAGE_EXTRAS))
|
||||
val messageExtraBytes = cursor.getBlob(cursor.getColumnIndexOrThrow(SNIPPET_MESSAGE_EXTRAS))
|
||||
val messageExtras = if (messageExtraBytes != null) MessageExtras.ADAPTER.decode(messageExtraBytes) else null
|
||||
val extra: Extra? = if (extraString != null) {
|
||||
try {
|
||||
val jsonObject = SaneJSONObject(JSONObject(extraString))
|
||||
@@ -1974,6 +1975,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
.setPinned(cursor.requireBoolean(PINNED))
|
||||
.setUnreadSelfMentionsCount(cursor.requireInt(UNREAD_SELF_MENTION_COUNT))
|
||||
.setExtra(extra)
|
||||
.setSnippetMessageExtras(messageExtras)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database.model
|
||||
|
||||
import ProtoUtil.isNullOrEmpty
|
||||
import okio.ByteString
|
||||
import org.signal.core.util.StringUtil
|
||||
import org.signal.storageservice.protos.groups.AccessControl
|
||||
import org.signal.storageservice.protos.groups.AccessControl.AccessRequired
|
||||
import org.signal.storageservice.protos.groups.Member
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember
|
||||
import org.signal.storageservice.protos.groups.local.EnabledState
|
||||
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.GroupExpirationTimerUpdate
|
||||
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.GroupMemberJoinedByLinkUpdate
|
||||
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.GroupSelfInvitationRevokedUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupSequenceOfRequestsAndCancelsUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupUnknownInviteeUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2AccessLevel
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedOtherUserToGroupUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedToGroupUpdate
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context
|
||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.Companion.parseOrNull
|
||||
import org.whispersystems.signalservice.api.push.ServiceIds
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil
|
||||
import java.util.LinkedList
|
||||
import java.util.Optional
|
||||
import java.util.stream.Collectors
|
||||
|
||||
/**
|
||||
* Object to help with the translation between DecryptedGroupV2Context group updates
|
||||
* and GroupChangeChatUpdates, which store the update messages as distinct messages rather
|
||||
* than diffs of the group state.
|
||||
*/
|
||||
object GroupsV2UpdateMessageConverter {
|
||||
|
||||
@JvmStatic
|
||||
fun translateDecryptedChange(selfIds: ServiceIds, groupContext: DecryptedGroupV2Context): GroupChangeChatUpdate {
|
||||
if (groupContext.change != null && ((groupContext.groupState != null && groupContext.groupState.revision != 0) || groupContext.previousGroupState != null)) {
|
||||
return translateDecryptedChangeUpdate(selfIds, groupContext)
|
||||
} else {
|
||||
return translateDecryptedChangeNewGroup(selfIds, groupContext)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateDecryptedChangeNewGroup(selfIds: ServiceIds, groupContext: DecryptedGroupV2Context): GroupChangeChatUpdate {
|
||||
var selfPending = Optional.empty<DecryptedPendingMember>()
|
||||
val decryptedGroupChange = groupContext.change
|
||||
val group = groupContext.groupState
|
||||
val updates: MutableList<GroupChangeChatUpdate.Update> = LinkedList()
|
||||
|
||||
if (group != null) {
|
||||
selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.aci)
|
||||
if (selfPending.isEmpty() && selfIds.pni != null) {
|
||||
selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.pni)
|
||||
}
|
||||
}
|
||||
|
||||
if (selfPending.isPresent) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
selfInvitedToGroupUpdate = SelfInvitedToGroupUpdate(inviterAci = selfPending.get().addedByAci)
|
||||
)
|
||||
)
|
||||
return GroupChangeChatUpdate(updates = updates)
|
||||
}
|
||||
|
||||
if (decryptedGroupChange != null) {
|
||||
val foundingMemberUuid: ByteString = decryptedGroupChange.editorServiceIdBytes
|
||||
if (foundingMemberUuid.size > 0) {
|
||||
if (selfIds.matches(foundingMemberUuid)) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupCreationUpdate = GroupCreationUpdate(updaterAci = foundingMemberUuid)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberAddedUpdate = GroupMemberAddedUpdate(updaterAci = foundingMemberUuid, newMemberAci = selfIds.aci.toByteString())
|
||||
)
|
||||
)
|
||||
}
|
||||
return GroupChangeChatUpdate(updates = updates)
|
||||
}
|
||||
}
|
||||
|
||||
if (group != null && DecryptedGroupUtil.findMemberByAci(group.members, selfIds.aci).isPresent) {
|
||||
updates.add(GroupChangeChatUpdate.Update(groupMemberJoinedUpdate = GroupMemberJoinedUpdate(newMemberAci = selfIds.aci.toByteString())))
|
||||
}
|
||||
return GroupChangeChatUpdate(updates = updates)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateDecryptedChangeUpdate(selfIds: ServiceIds, groupContext: DecryptedGroupV2Context): GroupChangeChatUpdate {
|
||||
var previousGroupState = groupContext.previousGroupState
|
||||
val change = groupContext.change!!
|
||||
if (DecryptedGroup().equals(previousGroupState)) {
|
||||
previousGroupState = null
|
||||
}
|
||||
val updates: MutableList<GroupChangeChatUpdate.Update> = LinkedList()
|
||||
var editorUnknown = change.editorServiceIdBytes.size == 0
|
||||
val editorServiceId = if (editorUnknown) null else parseOrNull(change.editorServiceIdBytes)
|
||||
if (editorServiceId == null || editorServiceId.isUnknown) {
|
||||
editorUnknown = true
|
||||
}
|
||||
translateMemberAdditions(change, editorUnknown, updates)
|
||||
translateModifyMemberRoles(change, editorUnknown, updates)
|
||||
translateInvitations(selfIds, change, editorUnknown, updates)
|
||||
translateRevokedInvitations(selfIds, change, editorUnknown, updates)
|
||||
translatePromotePending(selfIds, change, editorUnknown, updates)
|
||||
translateNewTitle(change, editorUnknown, updates)
|
||||
translateNewDescription(change, editorUnknown, updates)
|
||||
translateNewAvatar(change, editorUnknown, updates)
|
||||
translateNewTimer(change, editorUnknown, updates)
|
||||
translateNewAttributeAccess(change, editorUnknown, updates)
|
||||
translateNewMembershipAccess(change, editorUnknown, updates)
|
||||
translateNewGroupInviteLinkAccess(previousGroupState, change, editorUnknown, updates)
|
||||
translateRequestingMembers(selfIds, change, editorUnknown, updates)
|
||||
translateRequestingMemberApprovals(selfIds, change, editorUnknown, updates)
|
||||
translateRequestingMemberDeletes(selfIds, change, editorUnknown, updates)
|
||||
translateAnnouncementGroupChange(change, editorUnknown, updates)
|
||||
translatePromotePendingPniAci(selfIds, change, editorUnknown, updates)
|
||||
translateMemberRemovals(selfIds, change, editorUnknown, updates)
|
||||
if (updates.isEmpty()) {
|
||||
translateUnknownChange(change, editorUnknown, updates)
|
||||
}
|
||||
return GroupChangeChatUpdate(updates = updates)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateMemberAdditions(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
for (member in change.newMembers) {
|
||||
if (!editorUnknown && member.aciBytes == change.editorServiceIdBytes) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberJoinedByLinkUpdate = GroupMemberJoinedByLinkUpdate(newMemberAci = member.aciBytes)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberAddedUpdate = GroupMemberAddedUpdate(
|
||||
updaterAci = if (editorUnknown) null else change.editorServiceIdBytes,
|
||||
newMemberAci = member.aciBytes,
|
||||
hadOpenInvitation = false
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateModifyMemberRoles(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
for (roleChange in change.modifyMemberRoles) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupAdminStatusUpdate = GroupAdminStatusUpdate(
|
||||
updaterAci = if (editorUnknown) null else change.editorServiceIdBytes,
|
||||
memberAci = roleChange.aciBytes,
|
||||
wasAdminStatusGranted = roleChange.role == Member.Role.ADMINISTRATOR
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateInvitations(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val editorIsYou = selfIds.matches(change.editorServiceIdBytes)
|
||||
|
||||
var notYouInviteCount = 0
|
||||
for (invitee in change.newPendingMembers) {
|
||||
val newMemberIsYou = selfIds.matches(invitee.serviceIdBytes)
|
||||
if (newMemberIsYou) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
selfInvitedToGroupUpdate = SelfInvitedToGroupUpdate(
|
||||
inviterAci = if (editorUnknown) convertUnknownUUIDtoNull(invitee.addedByAci) else change.editorServiceIdBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
if (editorIsYou) {
|
||||
updates.add(GroupChangeChatUpdate.Update(selfInvitedOtherUserToGroupUpdate = SelfInvitedOtherUserToGroupUpdate(inviteeServiceId = invitee.serviceIdBytes)))
|
||||
} else {
|
||||
notYouInviteCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
if (notYouInviteCount > 0) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupUnknownInviteeUpdate = GroupUnknownInviteeUpdate(
|
||||
inviterAci = if (editorUnknown) null else change.editorServiceIdBytes,
|
||||
inviteeCount = notYouInviteCount
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateRevokedInvitations(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
|
||||
val revokedInvitees = LinkedList<GroupInvitationRevokedUpdate.Invitee>()
|
||||
|
||||
for (invitee in change.deletePendingMembers) {
|
||||
val decline = invitee.serviceIdBytes == editorAci
|
||||
if (decline) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInvitationDeclinedUpdate = GroupInvitationDeclinedUpdate(inviteeAci = invitee.serviceIdBytes)
|
||||
)
|
||||
)
|
||||
} else if (selfIds.matches(invitee.serviceIdBytes)) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupSelfInvitationRevokedUpdate = GroupSelfInvitationRevokedUpdate(revokerAci = editorAci)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
revokedInvitees.add(
|
||||
GroupInvitationRevokedUpdate.Invitee(
|
||||
inviteeAci = invitee.serviceIdBytes
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (revokedInvitees.isNotEmpty()) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInvitationRevokedUpdate = GroupInvitationRevokedUpdate(
|
||||
updaterAci = editorAci,
|
||||
invitees = revokedInvitees
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translatePromotePending(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
val editorIsYou = if (editorUnknown) false else selfIds.matches(editorAci)
|
||||
|
||||
for (member in change.promotePendingMembers) {
|
||||
val newMemberIsYou: Boolean = selfIds.matches(member.aciBytes)
|
||||
if (editorIsYou) {
|
||||
if (newMemberIsYou) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInvitationAcceptedUpdate = GroupInvitationAcceptedUpdate(
|
||||
inviterAci = null,
|
||||
newMemberAci = member.aciBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberAddedUpdate = GroupMemberAddedUpdate(
|
||||
updaterAci = editorAci,
|
||||
newMemberAci = member.aciBytes,
|
||||
hadOpenInvitation = true
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if (editorUnknown) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberJoinedUpdate = GroupMemberJoinedUpdate(
|
||||
newMemberAci = member.aciBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
} else if (member.aciBytes == change.editorServiceIdBytes) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInvitationAcceptedUpdate = GroupInvitationAcceptedUpdate(
|
||||
inviterAci = null,
|
||||
newMemberAci = member.aciBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberAddedUpdate = GroupMemberAddedUpdate(
|
||||
updaterAci = editorAci,
|
||||
newMemberAci = member.aciBytes,
|
||||
hadOpenInvitation = true
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewTitle(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newTitle != null) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
val newTitle = StringUtil.isolateBidi(change.newTitle?.value_)
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupNameUpdate = GroupNameUpdate(
|
||||
updaterAci = editorAci,
|
||||
newGroupName = newTitle
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewDescription(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newDescription != null) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupDescriptionUpdate = GroupDescriptionUpdate(
|
||||
updaterAci = editorAci,
|
||||
newDescription = change.newDescription?.value_
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewAvatar(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newAvatar != null) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupAvatarUpdate = GroupAvatarUpdate(
|
||||
updaterAci = editorAci,
|
||||
wasRemoved = change.newAvatar?.value_.isNullOrEmpty()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewTimer(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newTimer != null) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupExpirationTimerUpdate = GroupExpirationTimerUpdate(
|
||||
expiresInMs = change.newTimer!!.duration * 1000,
|
||||
updaterAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewAttributeAccess(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newAttributeAccess != AccessControl.AccessRequired.UNKNOWN) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupAttributesAccessLevelChangeUpdate = GroupAttributesAccessLevelChangeUpdate(
|
||||
updaterAci = editorAci,
|
||||
accessLevel = translateGv2AccessLevel(change.newAttributeAccess)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateGv2AccessLevel(accessRequired: AccessRequired): GroupV2AccessLevel {
|
||||
return when (accessRequired) {
|
||||
AccessRequired.ANY -> GroupV2AccessLevel.ANY
|
||||
AccessRequired.MEMBER -> GroupV2AccessLevel.MEMBER
|
||||
AccessRequired.ADMINISTRATOR -> GroupV2AccessLevel.ADMINISTRATOR
|
||||
AccessRequired.UNSATISFIABLE -> GroupV2AccessLevel.UNSATISFIABLE
|
||||
AccessRequired.UNKNOWN -> GroupV2AccessLevel.UNKNOWN
|
||||
else -> GroupV2AccessLevel.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewMembershipAccess(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newMemberAccess !== AccessRequired.UNKNOWN) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMembershipAccessLevelChangeUpdate = GroupMembershipAccessLevelChangeUpdate(
|
||||
updaterAci = editorAci,
|
||||
accessLevel = translateGv2AccessLevel(change.newMemberAccess)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewGroupInviteLinkAccess(previousGroupState: DecryptedGroup?, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
var previousAccessControl: AccessRequired? = null
|
||||
|
||||
if (previousGroupState?.accessControl != null) {
|
||||
previousAccessControl = previousGroupState.accessControl!!.addFromInviteLink
|
||||
}
|
||||
|
||||
var groupLinkEnabled = false
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
|
||||
when (change.newInviteLinkAccess) {
|
||||
AccessRequired.ANY -> {
|
||||
groupLinkEnabled = true
|
||||
updates.add(
|
||||
if (previousAccessControl == AccessControl.AccessRequired.ADMINISTRATOR) {
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInviteLinkAdminApprovalUpdate = GroupInviteLinkAdminApprovalUpdate(
|
||||
updaterAci = editorAci,
|
||||
linkRequiresAdminApproval = false
|
||||
)
|
||||
)
|
||||
} else {
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInviteLinkEnabledUpdate = GroupInviteLinkEnabledUpdate(
|
||||
updaterAci = editorAci,
|
||||
linkRequiresAdminApproval = false
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
AccessRequired.ADMINISTRATOR -> {
|
||||
groupLinkEnabled = true
|
||||
updates.add(
|
||||
if (previousAccessControl == AccessControl.AccessRequired.ANY) {
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInviteLinkAdminApprovalUpdate = GroupInviteLinkAdminApprovalUpdate(
|
||||
updaterAci = editorAci,
|
||||
linkRequiresAdminApproval = true
|
||||
)
|
||||
)
|
||||
} else {
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInviteLinkEnabledUpdate = GroupInviteLinkEnabledUpdate(
|
||||
updaterAci = editorAci,
|
||||
linkRequiresAdminApproval = true
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
AccessRequired.UNSATISFIABLE -> {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInviteLinkDisabledUpdate = GroupInviteLinkDisabledUpdate(
|
||||
updaterAci = editorAci
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
if (!groupLinkEnabled && change.newInviteLinkPassword.size > 0) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInviteLinkResetUpdate = GroupInviteLinkResetUpdate(
|
||||
updaterAci = editorAci
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateRequestingMembers(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val deleteRequestingUuids: Set<ByteString> = HashSet(change.deleteRequestingMembers)
|
||||
for (member in change.newRequestingMembers) {
|
||||
val requestingMemberIsYou = selfIds.matches(member.aciBytes)
|
||||
if (!requestingMemberIsYou && deleteRequestingUuids.contains(member.aciBytes)) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupSequenceOfRequestsAndCancelsUpdate = GroupSequenceOfRequestsAndCancelsUpdate(
|
||||
requestorAci = member.aciBytes,
|
||||
count = change.deleteRequestingMembers.size
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupJoinRequestUpdate = GroupJoinRequestUpdate(
|
||||
requestorAci = member.aciBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateRequestingMemberApprovals(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
for (requestingMember in change.promoteRequestingMembers) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupJoinRequestApprovalUpdate = GroupJoinRequestApprovalUpdate(
|
||||
updaterAci = editorAci,
|
||||
requestorAci = requestingMember.aciBytes,
|
||||
wasApproved = true
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateRequestingMemberDeletes(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val newRequestingUuids = change.newRequestingMembers.stream().map { m: DecryptedRequestingMember -> m.aciBytes }.collect(Collectors.toSet())
|
||||
|
||||
val editorIsYou = selfIds.matches(change.editorServiceIdBytes)
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
for (requestingMember in change.deleteRequestingMembers) {
|
||||
if (newRequestingUuids.contains(requestingMember)) {
|
||||
continue
|
||||
}
|
||||
|
||||
val requestingMemberIsYou = selfIds.matches(requestingMember)
|
||||
if ((requestingMemberIsYou && editorIsYou) || (change.editorServiceIdBytes == requestingMember)) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupJoinRequestCanceledUpdate = GroupJoinRequestCanceledUpdate(
|
||||
requestorAci = requestingMember
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupJoinRequestApprovalUpdate = GroupJoinRequestApprovalUpdate(
|
||||
requestorAci = requestingMember,
|
||||
updaterAci = editorAci,
|
||||
wasApproved = false
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateAnnouncementGroupChange(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newIsAnnouncementGroup == EnabledState.ENABLED || change.newIsAnnouncementGroup == EnabledState.DISABLED) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupAnnouncementOnlyChangeUpdate = GroupAnnouncementOnlyChangeUpdate(
|
||||
updaterAci = editorAci,
|
||||
isAnnouncementOnly = change.newIsAnnouncementGroup == EnabledState.ENABLED
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translatePromotePendingPniAci(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val editorIsYou = selfIds.matches(change.editorServiceIdBytes)
|
||||
for (newMember in change.promotePendingPniAciMembers) {
|
||||
if (editorUnknown) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberJoinedUpdate = GroupMemberJoinedUpdate(
|
||||
newMemberAci = newMember.aciBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
if ((selfIds.matches(newMember.aciBytes) && editorIsYou) || newMember.aciBytes == change.editorServiceIdBytes) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupInvitationAcceptedUpdate = GroupInvitationAcceptedUpdate(
|
||||
inviterAci = null,
|
||||
newMemberAci = newMember.aciBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberAddedUpdate = GroupMemberAddedUpdate(
|
||||
newMemberAci = newMember.aciBytes,
|
||||
updaterAci = change.editorServiceIdBytes,
|
||||
hadOpenInvitation = true,
|
||||
inviterAci = null
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateMemberRemovals(selfIds: ServiceIds, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
val editorIsYou: Boolean = selfIds.matches(change.editorServiceIdBytes)
|
||||
for (member in change.deleteMembers) {
|
||||
val removedMemberIsYou: Boolean = selfIds.matches(member)
|
||||
if ((editorIsYou && removedMemberIsYou) || member == change.editorServiceIdBytes) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberLeftUpdate = GroupMemberLeftUpdate(aci = member)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberRemovedUpdate = GroupMemberRemovedUpdate(
|
||||
removerAci = if (editorUnknown) null else change.editorServiceIdBytes,
|
||||
removedAci = member
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateUnknownChange(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
genericGroupUpdate = GenericGroupUpdate(
|
||||
updaterAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertUnknownUUIDtoNull(id: ByteString?): ByteString? {
|
||||
if (id.isNullOrEmpty()) return null
|
||||
val uuid = UuidUtil.fromByteStringOrUnknown(id)
|
||||
|
||||
if (UuidUtil.UNKNOWN_UUID == uuid) return null
|
||||
return id
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ 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.GroupExpirationTimerUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationAcceptedUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationDeclinedUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationRevokedUpdate;
|
||||
@@ -44,11 +45,13 @@ 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.GroupMemberJoinedByLinkUpdate;
|
||||
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.GroupSelfInvitationRevokedUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupUnknownInviteeUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2AccessLevel;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationDroppedMembersUpdate;
|
||||
@@ -57,6 +60,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationSelfInvitedUpd
|
||||
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.DecryptedGroupV2Context;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GV2UpdateDescription;
|
||||
import org.thoughtcrime.securesms.groups.GV2AccessLevelUtil;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
@@ -145,6 +149,9 @@ final class GroupsV2UpdateMessageProducer {
|
||||
for (GroupChangeChatUpdate.Update update : groupUpdates) {
|
||||
describeUpdate(update, updates);
|
||||
}
|
||||
if (updates.isEmpty()) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16));
|
||||
}
|
||||
|
||||
return updates;
|
||||
}
|
||||
@@ -210,6 +217,41 @@ final class GroupsV2UpdateMessageProducer {
|
||||
describeGroupV2MigrationInvitedMembersUpdate(update.groupV2MigrationInvitedMembersUpdate, updates);
|
||||
} else if (update.groupV2MigrationSelfInvitedUpdate != null) {
|
||||
describeGroupV2MigrationSelfInvitedUpdate(update.groupV2MigrationSelfInvitedUpdate, updates);
|
||||
} else if (update.groupMemberJoinedByLinkUpdate != null) {
|
||||
describeGroupMemberJoinedByLinkUpdate(update.groupMemberJoinedByLinkUpdate, updates);
|
||||
} else if (update.groupExpirationTimerUpdate != null) {
|
||||
describeGroupExpirationTimerUpdate(update.groupExpirationTimerUpdate, updates);
|
||||
} else if (update.groupSelfInvitationRevokedUpdate != null) {
|
||||
describeGroupSelfInvitationRevokedUpdate(update.groupSelfInvitationRevokedUpdate, updates);
|
||||
}
|
||||
}
|
||||
|
||||
private void describeGroupSelfInvitationRevokedUpdate(@NonNull GroupSelfInvitationRevokedUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||
if (update.revokerAci == null) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
|
||||
} else {
|
||||
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, update.revokerAci, R.drawable.ic_update_group_decline_16));
|
||||
}
|
||||
}
|
||||
private void describeGroupExpirationTimerUpdate(@NonNull GroupExpirationTimerUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||
String time = ExpirationUtil.getExpirationDisplayValue(context, update.expiresInMs / 1000);
|
||||
if (update.updaterAci == null) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_disappearing_message_time_set_to_s, time), R.drawable.ic_update_timer_16));
|
||||
} else {
|
||||
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||
if (editorIsYou) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16));
|
||||
} else {
|
||||
updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, update.updaterAci, time, R.drawable.ic_update_timer_16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void describeGroupMemberJoinedByLinkUpdate(@NonNull GroupMemberJoinedByLinkUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||
if (selfIds.matches(update.newMemberAci)) {
|
||||
updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group_via_the_group_link), R.drawable.ic_update_group_accept_16));
|
||||
} else {
|
||||
updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group_via_the_group_link, update.newMemberAci, R.drawable.ic_update_group_accept_16));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,12 +296,10 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
|
||||
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) {
|
||||
if (selfIds.matches(update.updaterAci)) {
|
||||
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));
|
||||
@@ -268,7 +308,6 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
|
||||
private void describeInviteLinkEnabledUpdate(@NonNull GroupInviteLinkEnabledUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||
|
||||
if (update.updaterAci == null) {
|
||||
if (update.linkRequiresAdminApproval) {
|
||||
@@ -277,7 +316,7 @@ final class GroupsV2UpdateMessageProducer {
|
||||
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 (selfIds.matches(update.updaterAci)) {
|
||||
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 {
|
||||
@@ -366,7 +405,7 @@ final class GroupsV2UpdateMessageProducer {
|
||||
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)) {
|
||||
if ((invitee.inviteeAci != null && selfIds.matches(invitee.inviteeAci)) || (invitee.inviteePni != null && selfIds.matches(invitee.inviteePni))) {
|
||||
revokedMeCount++;
|
||||
}
|
||||
}
|
||||
@@ -409,17 +448,21 @@ final class GroupsV2UpdateMessageProducer {
|
||||
} 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 if (selfIds.matches(update.updaterAci)) {
|
||||
if (update.hadOpenInvitation) {
|
||||
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_you_added_s, update.newMemberAci, 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));
|
||||
if (update.hadOpenInvitation) {
|
||||
updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, update.updaterAci, update.newMemberAci, 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,11 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
|
||||
public @Nullable UpdateDescription getUpdateDisplayBody(@NonNull Context context, @Nullable Consumer<RecipientId> recipientClickHandler) {
|
||||
if (isGroupUpdate() && isGroupV2()) {
|
||||
return getGv2ChangeDescription(context, getBody(), recipientClickHandler);
|
||||
if (messageExtras != null) {
|
||||
return getGv2ChangeDescription(context, messageExtras, recipientClickHandler);
|
||||
} else {
|
||||
return getGv2ChangeDescription(context, getBody(), recipientClickHandler);
|
||||
}
|
||||
} else if (isGroupUpdate() && isOutgoing()) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16);
|
||||
} else if (isGroupUpdate()) {
|
||||
|
||||
Reference in New Issue
Block a user