Add new name collision state management.

This commit is contained in:
Alex Hart
2024-04-18 15:53:39 -03:00
committed by Greyson Parrelli
parent 62cf3feeaa
commit 15d8a698c5
17 changed files with 861 additions and 164 deletions

View File

@@ -51,7 +51,7 @@ class ReviewCardRepository {
if (groupId != null) {
loadRecipientsForGroup(groupId, onRecipientsLoadedListener);
} else if (recipientId != null) {
loadSimilarRecipients(context, recipientId, onRecipientsLoadedListener);
loadSimilarRecipients(recipientId, onRecipientsLoadedListener);
} else {
throw new AssertionError();
}
@@ -113,34 +113,21 @@ class ReviewCardRepository {
private static void loadRecipientsForGroup(@NonNull GroupId.V2 groupId,
@NonNull OnRecipientsLoadedListener onRecipientsLoadedListener)
{
SignalExecutors.BOUNDED.execute(() -> onRecipientsLoadedListener.onRecipientsLoaded(ReviewUtil.getDuplicatedRecipients(groupId)));
SignalExecutors.BOUNDED.execute(() -> {
RecipientId groupRecipientId = SignalDatabase.recipients().getByGroupId(groupId).orElse(null);
if (groupRecipientId != null) {
onRecipientsLoadedListener.onRecipientsLoaded(SignalDatabase.nameCollisions().getCollisionsForThreadRecipientId(groupRecipientId));
} else {
onRecipientsLoadedListener.onRecipientsLoadFailed();
}
});
}
private static void loadSimilarRecipients(@NonNull Context context,
@NonNull RecipientId recipientId,
private static void loadSimilarRecipients(@NonNull RecipientId recipientId,
@NonNull OnRecipientsLoadedListener onRecipientsLoadedListener)
{
SignalExecutors.BOUNDED.execute(() -> {
Recipient resolved = Recipient.resolved(recipientId);
List<RecipientId> recipientIds = SignalDatabase.recipients()
.getSimilarRecipientIds(resolved);
if (recipientIds.isEmpty()) {
onRecipientsLoadedListener.onRecipientsLoadFailed();
return;
}
HashSet<RecipientId> ids = new HashSet<>(recipientIds);
ids.add(recipientId);
List<ReviewRecipient> recipients = Stream.of(ids)
.map(Recipient::resolved)
.map(ReviewRecipient::new)
.sorted(new ReviewRecipient.Comparator(context, recipientId))
.toList();
onRecipientsLoadedListener.onRecipientsLoaded(recipients);
onRecipientsLoadedListener.onRecipientsLoaded(SignalDatabase.nameCollisions().getCollisionsForThreadRecipientId(recipientId));
});
}

View File

@@ -13,11 +13,11 @@ public class ReviewRecipient {
private final Recipient recipient;
private final ProfileChangeDetails profileChangeDetails;
ReviewRecipient(@NonNull Recipient recipient) {
public ReviewRecipient(@NonNull Recipient recipient) {
this(recipient, null);
}
ReviewRecipient(@NonNull Recipient recipient, @Nullable ProfileChangeDetails profileChangeDetails) {
public ReviewRecipient(@NonNull Recipient recipient, @Nullable ProfileChangeDetails profileChangeDetails) {
this.recipient = recipient;
this.profileChangeDetails = profileChangeDetails;
}

View File

@@ -7,102 +7,15 @@ import androidx.annotation.WorkerThread;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.database.GroupTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.GroupRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.signal.core.util.Base64;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public final class ReviewUtil {
private ReviewUtil() { }
private static final long TIMEOUT = TimeUnit.HOURS.toMillis(24);
/**
* Checks a single recipient against the database to see whether duplicates exist.
* This should not be used in the context of a group, due to performance reasons.
*
* @param recipientId Id of the recipient we are interested in.
* @return Whether or not multiple recipients share this profile name.
*/
@WorkerThread
public static List<RecipientId> getRecipientsToPromptForReview(@NonNull RecipientId recipientId)
{
Recipient recipient = Recipient.resolved(recipientId);
if (recipient.isGroup() || recipient.isSystemContact()) {
return Collections.emptyList();
}
return Stream.of(SignalDatabase.recipients().getSimilarRecipientIds(recipient))
.filter(id -> !id.equals(recipientId))
.toList();
}
@WorkerThread
public static @NonNull List<ReviewRecipient> getDuplicatedRecipients(@NonNull GroupId.V2 groupId)
{
Context context = ApplicationDependencies.getApplication();
List<MessageRecord> profileChangeRecords = getProfileChangeRecordsForGroup(context, groupId);
if (profileChangeRecords.isEmpty()) {
return Collections.emptyList();
}
List<Recipient> members = SignalDatabase.groups()
.getGroupMembers(groupId, GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF);
List<ReviewRecipient> changed = Stream.of(profileChangeRecords)
.distinctBy(record -> record.getFromRecipient().getId())
.map(record -> new ReviewRecipient(record.getFromRecipient().resolve(), getProfileChangeDetails(record)))
.filter(recipient -> !recipient.getRecipient().isSystemContact())
.toList();
List<ReviewRecipient> results = new LinkedList<>();
for (ReviewRecipient recipient : changed) {
if (results.contains(recipient)) {
continue;
}
members.remove(recipient.getRecipient());
for (Recipient member : members) {
if (Objects.equals(member.getDisplayName(context), recipient.getRecipient().getDisplayName(context))) {
results.add(recipient);
results.add(new ReviewRecipient(member));
}
}
}
return results;
}
@WorkerThread
public static @NonNull List<MessageRecord> getProfileChangeRecordsForGroup(@NonNull Context context, @NonNull GroupId.V2 groupId) {
RecipientId recipientId = SignalDatabase.recipients().getByGroupId(groupId).get();
Long threadId = SignalDatabase.threads().getThreadIdFor(recipientId);
if (threadId == null) {
return Collections.emptyList();
} else {
return SignalDatabase.messages().getProfileChangeDetailsRecords(threadId, System.currentTimeMillis() - TIMEOUT);
}
}
@WorkerThread
public static int getGroupsInCommonCount(@NonNull Context context, @NonNull RecipientId recipientId) {
return Stream.of(SignalDatabase.groups()
@@ -112,12 +25,4 @@ public final class ReviewUtil {
.toList()
.size();
}
private static @NonNull ProfileChangeDetails getProfileChangeDetails(@NonNull MessageRecord messageRecord) {
try {
return ProfileChangeDetails.ADAPTER.decode(Base64.decode(messageRecord.getBody()));
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}