diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt index 39785bc3a..2a160b137 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt @@ -381,7 +381,7 @@ sealed class ConversationSettingsViewModel( private fun getLegacyGroupState(recipient: Recipient): LegacyGroupPreference.State { val showLegacyInfo = recipient.requireGroupId().isV1 - return if (showLegacyInfo && recipient.participants.size > FeatureFlags.groupLimits().hardLimit) { + return if (showLegacyInfo && recipient.participantIds.size > FeatureFlags.groupLimits().hardLimit) { LegacyGroupPreference.State.TOO_LARGE } else if (showLegacyInfo) { LegacyGroupPreference.State.UPGRADE diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java index 552c6f118..aa3739961 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java @@ -216,7 +216,7 @@ public class ContactSelectionListItem extends ConstraintLayout implements Recipi if (!recipient.isGroup()) { throw new AssertionError(); } - int memberCount = recipient.getParticipants().size(); + int memberCount = recipient.getParticipantIds().size(); return getContext().getResources().getQuantityString(R.plurals.contact_selection_list_item__number_of_members, memberCount, memberCount); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt index 9ce06771c..4c562592b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt @@ -101,7 +101,7 @@ object ContactSearchItems { number.visible = true val count = if (model.story.recipient.isGroup) { - model.story.recipient.participants.size + model.story.recipient.participantIds.size } else { model.story.viewerCount } @@ -227,8 +227,9 @@ object ContactSearchItems { protected open fun bindNumberField(model: T) { number.visible = getRecipient(model).isGroup if (getRecipient(model).isGroup) { - number.text = getRecipient(model).participants + number.text = getRecipient(model).participantIds .take(10) + .map { id -> Recipient.resolved(id) } .sortedWith(IsSelfComparator()).joinToString(", ") { if (it.isSelf) { context.getString(R.string.ConversationTitleView_you) diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt index 392c150e9..7e697bd3c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt @@ -84,7 +84,7 @@ open class ContactSearchPagedDataSourceRepository( open fun getGroupStories(): Set { return SignalDatabase.groups.groupsToDisplayAsStories.map { val recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromGroupId(it)) - ContactSearchData.Story(recipient, recipient.participants.size) + ContactSearchData.Story(recipient, recipient.participantIds.size) }.toSet() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt index 6ee6d5b62..e42c7a578 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt @@ -92,7 +92,7 @@ class ContactSearchViewModel( state.copy( groupStories = state.groupStories + groupStories.map { val recipient = Recipient.resolved(it.recipientId) - ContactSearchData.Story(recipient, recipient.participants.size) + ContactSearchData.Story(recipient, recipient.participantIds.size) } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index ce3e8bac4..eeddee001 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -329,8 +329,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.disposables.Disposable; import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; @@ -2359,8 +2357,8 @@ public class ConversationParentFragment extends Fragment return annotations; } - Set validRecipientIds = Stream.of(getRecipient().getParticipants()) - .map(r -> MentionAnnotation.idToMentionAnnotationValue(r.getId())) + Set validRecipientIds = Stream.of(getRecipient().getParticipantIds()) + .map(id -> MentionAnnotation.idToMentionAnnotationValue(id)) .collect(Collectors.toSet()); return Stream.of(annotations) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java index 19046c4b6..c80569a10 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java @@ -192,7 +192,9 @@ public class ConversationTitleView extends RelativeLayout { private void setGroupRecipientTitle(@NonNull Recipient recipient) { this.title.setText(recipient.getDisplayName(getContext())); - this.subtitle.setText(Stream.of(recipient.getParticipants()) + this.subtitle.setText(Stream.of(recipient.getParticipantIds()) + .limit(10) + .map(Recipient::resolved) .sorted((a, b) -> Boolean.compare(a.isSelf(), b.isSelf())) .map(r -> r.isSelf() ? getResources().getString(R.string.ConversationTitleView_you) : r.getDisplayName(getContext())) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListDataSource.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListDataSource.java index eed0333f7..d33420d34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListDataSource.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListDataSource.java @@ -59,9 +59,9 @@ abstract class ConversationListDataSource implements PagedDataSource load(int start, int length, @NonNull CancellationSignal cancellationSignal) { Stopwatch stopwatch = new Stopwatch("load(" + start + ", " + length + "), " + getClass().getSimpleName()); - List conversations = new ArrayList<>(length); - List recipients = new LinkedList<>(); - Set needsResolve = new HashSet<>(); + List conversations = new ArrayList<>(length); + List recipients = new LinkedList<>(); + Set needsResolve = new HashSet<>(); try (ConversationReader reader = new ConversationReader(getCursor(start, length))) { ThreadRecord record; @@ -70,7 +70,7 @@ abstract class ConversationListDataSource implements PagedDataSource { val threadDatabase = threads - val recipientsWithinInteractionThreshold: MutableSet = LinkedHashSet() + val recipientsWithinInteractionThreshold: MutableSet = LinkedHashSet() threadDatabase.readerFor(threadDatabase.getRecentPushConversationList(-1, false)).use { reader -> var record: ThreadRecord? = reader.next @@ -2900,15 +2900,16 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) : while (record != null && record.date > lastInteractionThreshold) { val recipient = Recipient.resolved(record.recipient.id) if (recipient.isGroup) { - recipientsWithinInteractionThreshold.addAll(recipient.participants) + recipientsWithinInteractionThreshold.addAll(recipient.participantIds) } else { - recipientsWithinInteractionThreshold.add(recipient) + recipientsWithinInteractionThreshold.add(recipient.id) } record = reader.next } } - return recipientsWithinInteractionThreshold + return Recipient.resolvedList(recipientsWithinInteractionThreshold) + .asSequence() .filterNot { it.isSelf } .filter { it.lastProfileFetchTime < lastProfileFetchThreshold } .take(limit) diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java index 752d64151..a48e1340b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java @@ -52,8 +52,8 @@ public final class GroupsV1MigrationUtil { throw new InvalidMigrationStateException(); } - if (groupRecipient.getParticipants().size() > FeatureFlags.groupLimits().getHardLimit()) { - Log.w(TAG, "Too many members! Size: " + groupRecipient.getParticipants().size()); + if (groupRecipient.getParticipantIds().size() > FeatureFlags.groupLimits().getHardLimit()) { + Log.w(TAG, "Too many members! Size: " + groupRecipient.getParticipantIds().size()); throw new InvalidMigrationStateException(); } @@ -86,7 +86,7 @@ public final class GroupsV1MigrationUtil { throw new InvalidMigrationStateException(); } - List registeredMembers = RecipientUtil.getEligibleForSending(groupRecipient.getParticipants()); + List registeredMembers = RecipientUtil.getEligibleForSending(Recipient.resolvedList(groupRecipient.getParticipantIds())); if (RecipientUtil.ensureUuidsAreAvailable(context, registeredMembers)) { Log.i(TAG, "Newly-discovered UUIDs. Getting fresh recipients."); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/migration/GroupsV1MigrationRepository.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/migration/GroupsV1MigrationRepository.java index ae00e0a1c..9f827a119 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/migration/GroupsV1MigrationRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/migration/GroupsV1MigrationRepository.java @@ -68,7 +68,8 @@ final class GroupsV1MigrationRepository { return new MigrationState(Collections.emptyList(), Collections.emptyList()); } - Set needsRefresh = Stream.of(group.getParticipants()) + List members = Recipient.resolvedList(group.getParticipantIds()); + Set needsRefresh = Stream.of(members) .filter(r -> r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED) .map(Recipient::getId) .collect(Collectors.toSet()); @@ -82,7 +83,7 @@ final class GroupsV1MigrationRepository { } try { - List registered = Stream.of(group.getParticipants()) + List registered = Stream.of(members) .filter(Recipient::isRegistered) .toList(); @@ -93,13 +94,13 @@ final class GroupsV1MigrationRepository { group = group.fresh(); - List ineligible = Stream.of(group.getParticipants()) + List ineligible = Stream.of(members) .filter(r -> !r.hasServiceId() || r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED || r.getRegistered() != RecipientDatabase.RegisteredState.REGISTERED) .toList(); - List invites = Stream.of(group.getParticipants()) + List invites = Stream.of(members) .filterNot(ineligible::contains) .filterNot(Recipient::isSelf) .filter(r -> r.getProfileKey() == null) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java index 67b597efa..c924c4841 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java @@ -21,7 +21,6 @@ import org.whispersystems.signalservice.api.crypto.ContentHint; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.messages.SendMessageResult; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; -import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; import java.io.IOException; @@ -57,15 +56,15 @@ public class GroupCallUpdateSendJob extends BaseJob { throw new AssertionError("We have a recipient, but it's not a V2 Group"); } - List recipients = Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants())) + List recipientIds = Stream.of(RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds()))) .filterNot(Recipient::isSelf) .map(Recipient::getId) .toList(); return new GroupCallUpdateSendJob(recipientId, eraId, - recipients, - recipients.size(), + recipientIds, + recipientIds.size(), new Parameters.Builder() .setQueue(conversationRecipient.getId().toQueueKey()) .setLifespan(TimeUnit.MINUTES.toMillis(5)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV1MigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV1MigrationJob.java index 1a8f7c6e1..2f37c995a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV1MigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV1MigrationJob.java @@ -96,7 +96,7 @@ public class GroupV1MigrationJob extends BaseJob { for (ThreadRecord thread : threads) { jobManager.add(new GroupV1MigrationJob(thread.getRecipient().getId())); - needsRefresh.addAll(Stream.of(thread.getRecipient().getParticipants()) + needsRefresh.addAll(Stream.of(Recipient.resolvedList(thread.getRecipient().getParticipantIds())) .filter(r -> r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED) .map(Recipient::getId) .toList()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java index 5d71def15..54bf69470 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java @@ -1,7 +1,5 @@ package org.thoughtcrime.securesms.jobs; -import android.content.Context; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; @@ -62,8 +60,11 @@ public class ProfileKeySendJob extends BaseJob { throw new AssertionError("Do not send profile keys directly for GV2"); } - List recipients = conversationRecipient.isGroup() ? Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants())).map(Recipient::getId).toList() - : Stream.of(conversationRecipient.getId()).toList(); + List recipients = conversationRecipient.isGroup() ? Stream.of(RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds()))) + .map(Recipient::getId) + .toList() + : Stream.of(conversationRecipient.getId()) + .toList(); recipients.remove(Recipient.self().getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java index 003c0502a..94a4888d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java @@ -77,7 +77,7 @@ public class ReactionSendJob extends BaseJob { } RecipientId selfId = Recipient.self().getId(); - List recipients = conversationRecipient.isGroup() ? RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants()) + List recipients = conversationRecipient.isGroup() ? RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds())) .stream() .map(Recipient::getId) .filter(r -> !r.equals(selfId)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java index 18054c621..55b2e1c9b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java @@ -72,7 +72,7 @@ public class RemoteDeleteSendJob extends BaseJob { return ApplicationDependencies.getJobManager().startChain(MultiDeviceStorySendSyncJob.create(message.getDateSent(), messageId)); } } else { - recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipants()).map(Recipient::getId).toList() + recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipantIds()).toList() : Stream.of(conversationRecipient.getId()).toList(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt index fe302f10c..0941721ae 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.mediasend.v2 +import androidx.annotation.WorkerThread import androidx.core.util.Consumer import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.schedulers.Schedulers @@ -27,12 +28,13 @@ object UntrustedRecords { } } + @WorkerThread private fun checkForBadIdentityRecordsSync(contactSearchKeys: Set): List { val recipients: List = contactSearchKeys .map { Recipient.resolved(it.recipientId) } .map { recipient -> when { - recipient.isGroup -> recipient.participants + recipient.isGroup -> Recipient.resolvedList(recipient.participantIds) recipient.isDistributionList -> Recipient.resolvedList(SignalDatabase.distributionLists.getMembers(recipient.distributionListId.get())) else -> listOf(recipient) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/AddMessageDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/AddMessageDialogFragment.kt index e2d8963a2..7c15789bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/AddMessageDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/AddMessageDialogFragment.kt @@ -153,8 +153,8 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a annotations } else { - val validRecipientIds: Set = recipient.participants - .map { r -> MentionAnnotation.idToMentionAnnotationValue(r.id) } + val validRecipientIds: Set = recipient.participantIds + .map { id -> MentionAnnotation.idToMentionAnnotationValue(id) } .toSet() annotations diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java index 2acfd44f9..1d076e6f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java @@ -102,7 +102,7 @@ final class MessageRequestRepository { } } else if (recipient.isPushV1Group()) { if (RecipientUtil.isMessageRequestAccepted(context, threadId)) { - if (recipient.getParticipants().size() > FeatureFlags.groupLimits().getHardLimit()) { + if (recipient.getParticipantIds().size() > FeatureFlags.groupLimits().getHardLimit()) { return MessageRequestState.DEPRECATED_GROUP_V1_TOO_LARGE; } else { return MessageRequestState.DEPRECATED_GROUP_V1; diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index 13d7392c2..6726c27fb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -963,7 +963,7 @@ public final class MessageContentProcessor { Recipient threadRecipient = targetThread.getRecipient().resolve(); - if (threadRecipient.isGroup() && !threadRecipient.getParticipants().contains(senderRecipient)) { + if (threadRecipient.isGroup() && !threadRecipient.getParticipantIds().contains(senderRecipient.getId())) { warn(String.valueOf(content.getTimestamp()), "[handleReaction] Reaction author is not in the group! timestamp: " + reaction.getTargetSentTimestamp() + " author: " + targetAuthor.getId()); return null; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipient.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipient.java index d5f5a312a..d4356da4f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipient.java @@ -152,19 +152,8 @@ public final class LiveRecipient { Log.w(TAG, "[Resolve][MAIN] " + getId(), new Throwable()); } - Recipient updated = fetchAndCacheRecipientFromDisk(getId()); - List participants = Stream.of(updated.getParticipants()) - .filter(Recipient::isResolving) - .map(Recipient::getId) - .map(this::fetchAndCacheRecipientFromDisk) - .toList(); - - for (Recipient participant : participants) { - participant.live().set(participant); - } - + Recipient updated = fetchAndCacheRecipientFromDisk(getId()); set(updated); - return updated; } @@ -188,16 +177,7 @@ public final class LiveRecipient { Log.w(TAG, "[Refresh][MAIN] " + id, new Throwable()); } - Recipient recipient = fetchAndCacheRecipientFromDisk(id); - List participants = Stream.of(recipient.getParticipants()) - .map(Recipient::getId) - .map(this::fetchAndCacheRecipientFromDisk) - .toList(); - - for (Recipient participant : participants) { - participant.live().set(participant); - } - + Recipient recipient = fetchAndCacheRecipientFromDisk(id); set(recipient); refreshForceNotify.postValue(new Object()); } @@ -231,9 +211,9 @@ public final class LiveRecipient { Optional groupRecord = groupDatabase.getGroup(record.getId()); if (groupRecord.isPresent()) { - String title = groupRecord.get().getTitle(); - List members = Stream.of(groupRecord.get().getMembers()).filterNot(RecipientId::isUnknown).map(this::fetchAndCacheRecipientFromDisk).toList(); - Optional avatarId = Optional.empty(); + String title = groupRecord.get().getTitle(); + List members = Stream.of(groupRecord.get().getMembers()).filterNot(RecipientId::isUnknown).toList(); + Optional avatarId = Optional.empty(); if (groupRecord.get().hasAvatar()) { avatarId = Optional.of(groupRecord.get().getAvatarId()); @@ -251,8 +231,8 @@ public final class LiveRecipient { // TODO [stories] We'll have to see what the perf is like for very large distribution lists. We may not be able to support fetching all the members. if (groupRecord != null) { - String title = groupRecord.isUnknown() ? null : groupRecord.getName(); - List members = Stream.of(groupRecord.getMembers()).filterNot(RecipientId::isUnknown).map(this::fetchAndCacheRecipientFromDisk).toList(); + String title = groupRecord.isUnknown() ? null : groupRecord.getName(); + List members = Stream.of(groupRecord.getMembers()).filterNot(RecipientId::isUnknown).toList(); return RecipientDetails.forDistributionList(title, members, record); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java index 96666cc2a..9c29654db 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -72,6 +72,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers; import static org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBannerTier; +@SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class Recipient { private static final String TAG = Log.tag(Recipient.class); @@ -91,7 +92,7 @@ public class Recipient { private final String email; private final GroupId groupId; private final DistributionListId distributionListId; - private final List participants; + private final List participantIds; private final Optional groupAvatarId; private final boolean isSelf; private final boolean blocked; @@ -368,7 +369,7 @@ public class Recipient { this.email = null; this.groupId = null; this.distributionListId = null; - this.participants = Collections.emptyList(); + this.participantIds = Collections.emptyList(); this.groupAvatarId = Optional.empty(); this.isSelf = false; this.blocked = false; @@ -426,7 +427,7 @@ public class Recipient { this.email = details.email; this.groupId = details.groupId; this.distributionListId = details.distributionListId; - this.participants = details.participants; + this.participantIds = details.participantIds; this.groupAvatarId = details.groupAvatarId; this.isSelf = details.isSelf; this.blocked = details.blocked; @@ -488,10 +489,12 @@ public class Recipient { public @Nullable String getGroupName(@NonNull Context context) { if (groupId != null && Util.isEmpty(this.groupName)) { - List others = participants.stream() - .filter(r -> !r.isSelf()) - .limit(MAX_MEMBER_NAMES) - .collect(Collectors.toList()); + RecipientId selfId = Recipient.self().getId(); + List others = participantIds.stream() + .filter(id -> !id.equals(selfId)) + .limit(MAX_MEMBER_NAMES) + .map(Recipient::resolved) + .collect(Collectors.toList()); Map shortNameCounts = new HashMap<>(); @@ -515,7 +518,7 @@ public class Recipient { } } - if (participants.stream().anyMatch(Recipient::isSelf)) { + if (participantIds.stream().anyMatch(id -> id.equals(selfId))) { names.add(context.getString(R.string.Recipient_you)); } @@ -861,11 +864,12 @@ public class Recipient { } public boolean isActiveGroup() { - return Stream.of(getParticipants()).anyMatch(Recipient::isSelf); + RecipientId selfId = Recipient.self().getId(); + return Stream.of(getParticipantIds()).anyMatch(p -> p.equals(selfId)); } - public @NonNull List getParticipants() { - return new ArrayList<>(participants); + public @NonNull List getParticipantIds() { + return new ArrayList<>(participantIds); } public @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted) { @@ -1277,7 +1281,7 @@ public class Recipient { Objects.equals(e164, other.e164) && Objects.equals(email, other.email) && Objects.equals(groupId, other.groupId) && - allContentsAreTheSame(participants, other.participants) && + Objects.equals(participantIds, other.participantIds) && Objects.equals(groupAvatarId, other.groupAvatarId) && messageVibrate == other.messageVibrate && callVibrate == other.callVibrate && diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java index a1db43800..81697b570 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java @@ -54,7 +54,7 @@ public class RecipientDetails { final VibrateState callVibrateState; final boolean blocked; final int expireMessages; - final List participants; + final List participantIds; final ProfileName profileName; final Optional defaultSubscriptionId; final RegisteredState registered; @@ -96,7 +96,7 @@ public class RecipientDetails { boolean isSelf, @NonNull RegisteredState registeredState, @NonNull RecipientRecord record, - @Nullable List participants, + @Nullable List participantIds, boolean isReleaseChannel) { this.groupAvatarId = groupAvatarId; @@ -117,7 +117,7 @@ public class RecipientDetails { this.callVibrateState = record.getCallVibrateState(); this.blocked = record.isBlocked(); this.expireMessages = record.getExpireMessages(); - this.participants = participants == null ? new LinkedList<>() : participants; + this.participantIds = participantIds == null ? new LinkedList<>() : participantIds; this.profileName = record.getProfileName(); this.defaultSubscriptionId = record.getDefaultSubscriptionId(); this.registered = registeredState; @@ -174,7 +174,7 @@ public class RecipientDetails { this.callVibrateState = VibrateState.DEFAULT; this.blocked = false; this.expireMessages = 0; - this.participants = new LinkedList<>(); + this.participantIds = new LinkedList<>(); this.profileName = ProfileName.EMPTY; this.insightsBannerTier = InsightsBannerTier.TIER_TWO; this.defaultSubscriptionId = Optional.empty(); @@ -231,7 +231,7 @@ public class RecipientDetails { return new RecipientDetails(null, settings.getSystemDisplayName(), Optional.empty(), systemContact, isSelf, registeredState, settings, null, isReleaseChannel); } - public static @NonNull RecipientDetails forDistributionList(String title, @Nullable List members, @NonNull RecipientRecord record) { + public static @NonNull RecipientDetails forDistributionList(String title, @Nullable List members, @NonNull RecipientRecord record) { return new RecipientDetails(title, null, Optional.empty(), false, false, record.getRegistered(), record, members, false); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetRepository.kt index 3c585a2f2..a21ed6416 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetRepository.kt @@ -187,7 +187,7 @@ class SafetyNumberBottomSheetRepository { } private fun getGroupMemberships(recipient: Recipient, groups: List): List { - return groups.filter { it.participants.contains(recipient) } + return groups.filter { it.participantIds.contains(recipient.id) } } data class ResolvedIdentity(val recipient: Recipient, val identityRecord: Optional) diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java index afe6f06e6..44556c086 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java @@ -17,7 +17,6 @@ import org.signal.core.util.ThreadUtil; import org.signal.core.util.concurrent.SimpleTask; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.attachments.Attachment; -import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey; import org.thoughtcrime.securesms.conversation.MessageSendType; import org.thoughtcrime.securesms.conversation.colors.ChatColors; @@ -36,7 +35,6 @@ import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryBackgroundColors; import org.thoughtcrime.securesms.mms.ImageSlide; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage; -import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.mms.SentMediaQuality; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideDeck; @@ -57,6 +55,7 @@ import org.thoughtcrime.securesms.util.Util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Objects; @@ -480,10 +479,7 @@ public final class MultiShareSender { if (mentions.isEmpty() || !recipient.isPushV2Group() || !recipient.isActiveGroup()) { return Collections.emptyList(); } else { - Set validRecipientIds = recipient.getParticipants() - .stream() - .map(Recipient::getId) - .collect(Collectors.toSet()); + Set validRecipientIds = new HashSet<>(recipient.getParticipantIds()); return mentions.stream() .filter(mention -> validRecipientIds.contains(mention.getRecipientId())) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt index da10ebe33..f5a7152ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt @@ -436,8 +436,8 @@ class StoryGroupReplyFragment : annotations } else { - val validRecipientIds: Set = recipient.participants - .map { r -> MentionAnnotation.idToMentionAnnotationValue(r.id) } + val validRecipientIds: Set = recipient.participantIds + .map { id -> MentionAnnotation.idToMentionAnnotationValue(id) } .toSet() annotations diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt b/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt index 792350528..2e97eba2a 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt @@ -30,7 +30,7 @@ object RecipientDatabaseTestUtils { groupAvatarId: Optional = Optional.empty(), systemContact: Boolean = false, isSelf: Boolean = false, - participants: List = listOf(), + participants: List = listOf(), recipientId: RecipientId = RecipientId.from(Random.nextLong()), serviceId: ServiceId? = ServiceId.from(UUID.randomUUID()), username: String? = null,