Add search by group membership.

This commit is contained in:
Cody Henthorne 2022-08-24 15:54:21 -04:00 committed by Greyson Parrelli
parent 777a91abc7
commit a9fc5622cd
4 changed files with 82 additions and 4 deletions

View file

@ -300,6 +300,11 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
private @Nullable String getHeaderLetterForDisplayName(@NonNull Cursor cursor) {
String name = CursorUtil.requireString(cursor, ContactRepository.NAME_COLUMN);
if (name == null) {
return null;
}
Iterator<String> characterIterator = new CharacterIterable(name).iterator();
if (!TextUtils.isEmpty(name) && characterIterator.hasNext()) {

View file

@ -22,18 +22,26 @@ import android.database.MatrixCursor;
import androidx.annotation.NonNull;
import org.signal.core.util.CursorUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.UsernameUtil;
import org.whispersystems.signalservice.internal.util.Util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* CursorLoader that initializes a ContactsDatabase instance
@ -214,12 +222,35 @@ public class ContactsCursorLoader extends AbstractContactsCursorLoader {
private Cursor getGroupsCursor() {
MatrixCursor groupContacts = ContactsCursorRows.createMatrixCursor();
Map<RecipientId, GroupDatabase.GroupRecord> groups = new LinkedHashMap<>();
try (GroupDatabase.Reader reader = SignalDatabase.groups().queryGroupsByTitle(getFilter(), flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode), !smsEnabled(mode))) {
GroupDatabase.GroupRecord groupRecord;
while ((groupRecord = reader.getNext()) != null) {
groups.put(groupRecord.getRecipientId(), groupRecord);
}
}
if (getFilter() != null && !Util.isEmpty(getFilter())) {
Set<RecipientId> filteredContacts = new HashSet<>();
try (Cursor cursor = SignalDatabase.recipients().queryAllContacts(getFilter())) {
while (cursor != null && cursor.moveToNext()) {
filteredContacts.add(RecipientId.from(CursorUtil.requireString(cursor, RecipientDatabase.ID)));
}
}
try (GroupDatabase.Reader reader = SignalDatabase.groups().queryGroupsByMembership(filteredContacts, flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode), !smsEnabled(mode))) {
GroupDatabase.GroupRecord groupRecord;
while ((groupRecord = reader.getNext()) != null) {
groups.put(groupRecord.getRecipientId(), groupRecord);
}
}
}
for (GroupDatabase.GroupRecord groupRecord : groups.values()) {
groupContacts.addRow(ContactsCursorRows.forGroup(groupRecord));
}
}
return groupContacts;
}

View file

@ -294,6 +294,40 @@ public class GroupDatabase extends Database {
return new Reader(cursor);
}
public Reader queryGroupsByMembership(@NonNull Set<RecipientId> recipientIds, boolean includeInactive, boolean excludeV1, boolean excludeMms) {
if (recipientIds.isEmpty()) {
return new Reader(null);
}
List<String> recipientLikeClauses = recipientIds.stream()
.map(RecipientId::toLong)
.map(id -> "(" + MEMBERS + " LIKE " + id + " || ',%' OR " + MEMBERS + " LIKE '%,' || " + id + " || ',%' OR " + MEMBERS + " LIKE '%,' || " + id + ")")
.collect(Collectors.toList());
String query;
String[] queryArgs;
String membershipQuery = "(" + Util.join(recipientLikeClauses, " OR ") + ")";
if (includeInactive) {
query = membershipQuery + " AND (" + ACTIVE + " = ? OR " + RECIPIENT_ID + " IN (SELECT " + ThreadDatabase.RECIPIENT_ID + " FROM " + ThreadDatabase.TABLE_NAME + "))";
queryArgs = SqlUtil.buildArgs(1);
} else {
query = membershipQuery + " AND " + ACTIVE + " = ?";
queryArgs = SqlUtil.buildArgs(1);
}
if (excludeV1) {
query += " AND " + EXPECTED_V2_ID + " IS NULL";
}
if (excludeMms) {
query += " AND " + MMS + " = 0";
}
return new Reader(getReadableDatabase().query(TABLE_NAME, null, query, queryArgs, null, null, null));
}
public Reader queryGroupsByRecency(@NonNull GroupQuery groupQuery) {
SqlUtil.Query query = getGroupQueryWhereStatement(groupQuery.searchQuery, groupQuery.includeInactive, !groupQuery.includeV1, !groupQuery.includeMms);
String sql = "SELECT * FROM " + TABLE_NAME +

View file

@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import org.signal.core.util.CursorUtil;
import org.signal.core.util.concurrent.LatestPrioritizedSerialExecutor;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
@ -29,7 +30,6 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.signal.core.util.CursorUtil;
import org.thoughtcrime.securesms.util.FtsUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
@ -161,11 +161,13 @@ public class SearchRepository {
Set<RecipientId> recipientIds = new LinkedHashSet<>();
Set<RecipientId> filteredContacts = new LinkedHashSet<>();
try (Cursor cursor = SignalDatabase.recipients().queryAllContacts(query)) {
while (cursor != null && cursor.moveToNext()) {
recipientIds.add(RecipientId.from(CursorUtil.requireString(cursor, RecipientDatabase.ID)));
filteredContacts.add(RecipientId.from(CursorUtil.requireString(cursor, RecipientDatabase.ID)));
}
}
recipientIds.addAll(filteredContacts);
GroupDatabase.GroupRecord record;
try (GroupDatabase.Reader reader = SignalDatabase.groups().queryGroupsByTitle(query, true, false, false)) {
@ -174,6 +176,12 @@ public class SearchRepository {
}
}
try (GroupDatabase.Reader reader = SignalDatabase.groups().queryGroupsByMembership(filteredContacts, true, false, false)) {
while ((record = reader.getNext()) != null) {
recipientIds.add(record.getRecipientId());
}
}
if (noteToSelfTitle.toLowerCase().contains(query.toLowerCase())) {
recipientIds.add(Recipient.self().getId());
}