Sort "new group story" entries by recency.

This commit is contained in:
Alex Hart 2022-08-16 16:59:37 -03:00 committed by Cody Henthorne
parent 28310a88f5
commit e517232172
5 changed files with 116 additions and 6 deletions

View file

@ -63,6 +63,7 @@ class ContactSearchConfiguration private constructor(
val includeV1: Boolean = false, val includeV1: Boolean = false,
val includeInactive: Boolean = false, val includeInactive: Boolean = false,
val returnAsGroupStories: Boolean = false, val returnAsGroupStories: Boolean = false,
val sortOrder: ContactSearchSortOrder = ContactSearchSortOrder.NATURAL,
override val includeHeader: Boolean, override val includeHeader: Boolean,
override val expandConfig: ExpandConfig? = null override val expandConfig: ExpandConfig? = null
) : Section(SectionKey.GROUPS) ) : Section(SectionKey.GROUPS)

View file

@ -41,8 +41,19 @@ open class ContactSearchPagedDataSourceRepository(
return contactRepository.queryNonGroupContacts(query ?: "", includeSelf) return contactRepository.queryNonGroupContacts(query ?: "", includeSelf)
} }
open fun getGroupContacts(section: ContactSearchConfiguration.Section.Groups, query: String?): Cursor? { open fun getGroupContacts(
return SignalDatabase.groups.queryGroupsByTitle(query ?: "", section.includeInactive, !section.includeV1, !section.includeMms).cursor section: ContactSearchConfiguration.Section.Groups,
query: String?
): Cursor? {
return SignalDatabase.groups.queryGroups(
GroupDatabase.GroupQuery.Builder()
.withSearchQuery(query)
.withInactiveGroups(section.includeInactive)
.withMmsGroups(section.includeMms)
.withV1Groups(section.includeV1)
.withSortOrder(section.sortOrder)
.build()
).cursor
} }
open fun getRecents(section: ContactSearchConfiguration.Section.Recents): Cursor? { open fun getRecents(section: ContactSearchConfiguration.Section.Recents): Cursor? {

View file

@ -0,0 +1,19 @@
package org.thoughtcrime.securesms.contacts.paged
/**
* Different options for sort order of contact search items.
*/
enum class ContactSearchSortOrder {
/**
* The "natural" expected order. This is considered the default ordering.
* For example, Groups would normally be ordered by title from A-Z.
*/
NATURAL,
/**
* The requested ordering is by recency. This can mean different things for
* different contact types. For example, for Groups, this entry means that
* the results are ordered by latest message date in descending order.
*/
RECENCY
}

View file

@ -24,6 +24,7 @@ import org.signal.storageservice.protos.groups.Member;
import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.protos.groups.local.EnabledState; import org.signal.storageservice.protos.groups.local.EnabledState;
import org.thoughtcrime.securesms.contacts.paged.ContactSearchSortOrder;
import org.thoughtcrime.securesms.crypto.SenderKeyUtil; import org.thoughtcrime.securesms.crypto.SenderKeyUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.BadGroupIdException; import org.thoughtcrime.securesms.groups.BadGroupIdException;
@ -287,6 +288,31 @@ public class GroupDatabase extends Database {
} }
public Reader queryGroupsByTitle(String inputQuery, boolean includeInactive, boolean excludeV1, boolean excludeMms) { public Reader queryGroupsByTitle(String inputQuery, boolean includeInactive, boolean excludeV1, boolean excludeMms) {
SqlUtil.Query query = getGroupQueryWhereStatement(inputQuery, includeInactive, excludeV1, excludeMms);
Cursor cursor = databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, query.getWhere(), query.getWhereArgs(), null, null, TITLE + " COLLATE NOCASE ASC");
return new Reader(cursor);
}
public Reader queryGroupsByRecency(@NonNull GroupQuery groupQuery) {
SqlUtil.Query query = getGroupQueryWhereStatement(groupQuery.searchQuery, groupQuery.includeInactive, !groupQuery.includeV1, !groupQuery.includeMms);
String sql = "SELECT * FROM " + TABLE_NAME +
" LEFT JOIN " + ThreadDatabase.TABLE_NAME + " ON " + RECIPIENT_ID + " = " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID +
" WHERE " + query.getWhere() +
" ORDER BY " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.DATE + " DESC";
return new Reader(databaseHelper.getSignalReadableDatabase().rawQuery(sql, query.getWhereArgs()));
}
public Reader queryGroups(@NonNull GroupQuery groupQuery) {
if (groupQuery.sortOrder == ContactSearchSortOrder.NATURAL) {
return queryGroupsByTitle(groupQuery.searchQuery, groupQuery.includeInactive, !groupQuery.includeV1, !groupQuery.includeMms);
} else {
return queryGroupsByRecency(groupQuery);
}
}
private @NonNull SqlUtil.Query getGroupQueryWhereStatement(String inputQuery, boolean includeInactive, boolean excludeV1, boolean excludeMms) {
String query; String query;
String[] queryArgs; String[] queryArgs;
@ -308,9 +334,7 @@ public class GroupDatabase extends Database {
query += " AND " + MMS + " = 0"; query += " AND " + MMS + " = 0";
} }
Cursor cursor = databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, query, queryArgs, null, null, TITLE + " COLLATE NOCASE ASC"); return new SqlUtil.Query(query, queryArgs);
return new Reader(cursor);
} }
public @NonNull DistributionId getOrCreateDistributionId(@NonNull GroupId.V2 groupId) { public @NonNull DistributionId getOrCreateDistributionId(@NonNull GroupId.V2 groupId) {
@ -1445,6 +1469,59 @@ public class GroupDatabase extends Database {
} }
} }
public static class GroupQuery {
private final String searchQuery;
private final boolean includeInactive;
private final boolean includeV1;
private final boolean includeMms;
private final ContactSearchSortOrder sortOrder;
private GroupQuery(@NonNull Builder builder) {
this.searchQuery = builder.searchQuery;
this.includeInactive = builder.includeInactive;
this.includeV1 = builder.includeV1;
this.includeMms = builder.includeMms;
this.sortOrder = builder.sortOrder;
}
public static class Builder {
private String searchQuery = "";
private boolean includeInactive = false;
private boolean includeV1 = false;
private boolean includeMms = false;
private ContactSearchSortOrder sortOrder = ContactSearchSortOrder.NATURAL;
public @NonNull Builder withSearchQuery(@Nullable String query) {
this.searchQuery = TextUtils.isEmpty(query) ? "" : query;
return this;
}
public @NonNull Builder withInactiveGroups(boolean includeInactive) {
this.includeInactive = includeInactive;
return this;
}
public @NonNull Builder withV1Groups(boolean includeV1Groups) {
this.includeV1 = includeV1Groups;
return this;
}
public @NonNull Builder withMmsGroups(boolean includeMmsGroups) {
this.includeMms = includeMmsGroups;
return this;
}
public @NonNull Builder withSortOrder(@NonNull ContactSearchSortOrder sortOrder) {
this.sortOrder = sortOrder;
return this;
}
public GroupQuery build() {
return new GroupQuery(this);
}
}
}
public static class LegacyGroupInsertException extends IllegalStateException { public static class LegacyGroupInsertException extends IllegalStateException {
public LegacyGroupInsertException(@Nullable GroupId id) { public LegacyGroupInsertException(@Nullable GroupId id) {
super("Tried to create a new GV1 entry when we already had a migrated GV2! " + id); super("Tried to create a new GV1 entry when we already had a migrated GV2! " + id);

View file

@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.components.FixedRoundedCornerBottomSheetDialog
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.contacts.paged.ContactSearchMediator import org.thoughtcrime.securesms.contacts.paged.ContactSearchMediator
import org.thoughtcrime.securesms.contacts.paged.ContactSearchSortOrder
import org.thoughtcrime.securesms.sharing.ShareContact import org.thoughtcrime.securesms.sharing.ShareContact
import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter
import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel
@ -73,7 +74,8 @@ class ChooseGroupStoryBottomSheet : FixedRoundedCornerBottomSheetDialogFragment(
addSection( addSection(
ContactSearchConfiguration.Section.Groups( ContactSearchConfiguration.Section.Groups(
includeHeader = false, includeHeader = false,
returnAsGroupStories = true returnAsGroupStories = true,
sortOrder = ContactSearchSortOrder.RECENCY
) )
) )
} }