mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Add group member results to contact search.
This commit is contained in:
committed by
Greyson Parrelli
parent
eaeeb08987
commit
c022172ace
@@ -131,6 +131,14 @@ public class ContactRepository {
|
||||
return new SearchCursorWrapper(cursor, SEARCH_CURSOR_MAPPERS);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public @NonNull Cursor queryGroupMemberContacts(@NonNull String query) {
|
||||
Cursor cursor = TextUtils.isEmpty(query) ? recipientTable.getGroupMemberContacts()
|
||||
: recipientTable.queryGroupMemberContacts(query);
|
||||
|
||||
return new SearchCursorWrapper(cursor, SEARCH_CURSOR_MAPPERS);
|
||||
}
|
||||
|
||||
private @NonNull Cursor handleNoteToSelfQuery(@NonNull String query, boolean includeSelf, Cursor cursor) {
|
||||
if (includeSelf && noteToSelfTitle.toLowerCase().contains(query.toLowerCase())) {
|
||||
Recipient self = Recipient.self();
|
||||
|
||||
@@ -272,10 +272,13 @@ open class ContactSearchAdapter(
|
||||
override fun getRecipient(model: RecipientModel): Recipient = model.knownRecipient.recipient
|
||||
override fun bindNumberField(model: RecipientModel) {
|
||||
val recipient = getRecipient(model)
|
||||
|
||||
if (model.shortSummary && recipient.isGroup) {
|
||||
if (model.knownRecipient.sectionKey == ContactSearchConfiguration.SectionKey.GROUP_MEMBERS) {
|
||||
number.text = model.knownRecipient.groupsInCommon.toDisplayText(context)
|
||||
number.visible = true
|
||||
} else if (model.shortSummary && recipient.isGroup) {
|
||||
val count = recipient.participantIds.size
|
||||
number.text = context.resources.getQuantityString(R.plurals.ContactSearchItems__group_d_members, count, count)
|
||||
number.visible = true
|
||||
} else {
|
||||
super.bindNumberField(model)
|
||||
}
|
||||
@@ -404,6 +407,7 @@ open class ContactSearchAdapter(
|
||||
ContactSearchConfiguration.SectionKey.INDIVIDUALS -> R.string.ContactsCursorLoader_contacts
|
||||
ContactSearchConfiguration.SectionKey.GROUPS -> R.string.ContactsCursorLoader_groups
|
||||
ContactSearchConfiguration.SectionKey.ARBITRARY -> error("This section does not support HEADER")
|
||||
ContactSearchConfiguration.SectionKey.GROUP_MEMBERS -> R.string.ContactsCursorLoader_group_members
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -76,17 +76,47 @@ class ContactSearchConfiguration private constructor(
|
||||
override val includeHeader: Boolean = false
|
||||
override val expandConfig: ExpandConfig? = null
|
||||
}
|
||||
|
||||
data class GroupMembers(
|
||||
override val includeHeader: Boolean = true,
|
||||
override val expandConfig: ExpandConfig? = null
|
||||
) : Section(SectionKey.GROUP_MEMBERS)
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a given section. Useful for labeling sections and managing expansion state.
|
||||
*/
|
||||
enum class SectionKey {
|
||||
/**
|
||||
* Lists My Stories, distribution lists, as well as group stories.
|
||||
*/
|
||||
STORIES,
|
||||
|
||||
/**
|
||||
* Recent chats.
|
||||
*/
|
||||
RECENTS,
|
||||
|
||||
/**
|
||||
* 1:1 Contacts with whom I've started a chat.
|
||||
*/
|
||||
INDIVIDUALS,
|
||||
|
||||
/**
|
||||
* Active groups the user is a member of
|
||||
*/
|
||||
GROUPS,
|
||||
ARBITRARY
|
||||
|
||||
/**
|
||||
* Arbitrary row (think new group button, username row, etc)
|
||||
*/
|
||||
ARBITRARY,
|
||||
|
||||
/**
|
||||
* Contacts that are members of groups user is in that they've not explicitly
|
||||
* started a conversation with.
|
||||
*/
|
||||
GROUP_MEMBERS
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,9 +25,11 @@ sealed class ContactSearchData(val contactSearchKey: ContactSearchKey) {
|
||||
* A row displaying a known recipient.
|
||||
*/
|
||||
data class KnownRecipient(
|
||||
val sectionKey: ContactSearchConfiguration.SectionKey,
|
||||
val recipient: Recipient,
|
||||
val shortSummary: Boolean = false,
|
||||
val headerLetter: String? = null
|
||||
val headerLetter: String? = null,
|
||||
val groupsInCommon: GroupsInCommon = GroupsInCommon(0, listOf())
|
||||
) : ContactSearchData(ContactSearchKey.RecipientSearchKey(recipient.id, false))
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,6 +91,7 @@ class ContactSearchPagedDataSource(
|
||||
is ContactSearchConfiguration.Section.Recents -> getRecentsSearchIterator(section, query).getCollectionSize(section, query, null)
|
||||
is ContactSearchConfiguration.Section.Stories -> getStoriesSearchIterator(query).getCollectionSize(section, query, null)
|
||||
is ContactSearchConfiguration.Section.Arbitrary -> arbitraryRepository?.getSize(section, query) ?: error("Invalid arbitrary section.")
|
||||
is ContactSearchConfiguration.Section.GroupMembers -> getGroupMembersSearchIterator(query).getCollectionSize(section, query, null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +123,7 @@ class ContactSearchPagedDataSource(
|
||||
is ContactSearchConfiguration.Section.Recents -> getRecentsContactData(section, query, startIndex, endIndex)
|
||||
is ContactSearchConfiguration.Section.Stories -> getStoriesContactData(section, query, startIndex, endIndex)
|
||||
is ContactSearchConfiguration.Section.Arbitrary -> arbitraryRepository?.getData(section, query, startIndex, endIndex) ?: error("Invalid arbitrary section.")
|
||||
is ContactSearchConfiguration.Section.GroupMembers -> getGroupMembersContactData(section, query, startIndex, endIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +154,10 @@ class ContactSearchPagedDataSource(
|
||||
return CursorSearchIterator(contactSearchPagedDataSourceRepository.getRecents(section))
|
||||
}
|
||||
|
||||
private fun getGroupMembersSearchIterator(query: String?): ContactSearchIterator<Cursor> {
|
||||
return CursorSearchIterator(contactSearchPagedDataSourceRepository.queryGroupMemberContacts(query))
|
||||
}
|
||||
|
||||
private fun <R> readContactData(
|
||||
records: ContactSearchIterator<R>,
|
||||
recordsPredicate: ((R) -> Boolean)?,
|
||||
@@ -197,7 +203,7 @@ class ContactSearchPagedDataSource(
|
||||
startIndex = startIndex,
|
||||
endIndex = endIndex,
|
||||
recordMapper = {
|
||||
ContactSearchData.KnownRecipient(contactSearchPagedDataSourceRepository.getRecipientFromThreadCursor(it))
|
||||
ContactSearchData.KnownRecipient(section.sectionKey, contactSearchPagedDataSourceRepository.getRecipientFromThreadCursor(it))
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -219,7 +225,7 @@ class ContactSearchPagedDataSource(
|
||||
endIndex = endIndex,
|
||||
recordMapper = {
|
||||
val recipient = contactSearchPagedDataSourceRepository.getRecipientFromRecipientCursor(it)
|
||||
ContactSearchData.KnownRecipient(recipient, headerLetter = headerMap[recipient.id])
|
||||
ContactSearchData.KnownRecipient(section.sectionKey, recipient, headerLetter = headerMap[recipient.id])
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -237,7 +243,7 @@ class ContactSearchPagedDataSource(
|
||||
if (section.returnAsGroupStories) {
|
||||
ContactSearchData.Story(contactSearchPagedDataSourceRepository.getRecipientFromGroupRecord(it), 0, DistributionListPrivacyMode.ALL)
|
||||
} else {
|
||||
ContactSearchData.KnownRecipient(contactSearchPagedDataSourceRepository.getRecipientFromGroupRecord(it), shortSummary = section.shortSummary)
|
||||
ContactSearchData.KnownRecipient(section.sectionKey, contactSearchPagedDataSourceRepository.getRecipientFromGroupRecord(it), shortSummary = section.shortSummary)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -254,6 +260,23 @@ class ContactSearchPagedDataSource(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGroupMembersContactData(section: ContactSearchConfiguration.Section.GroupMembers, query: String?, startIndex: Int, endIndex: Int): List<ContactSearchData> {
|
||||
return getGroupMembersSearchIterator(query).use { records ->
|
||||
readContactData(
|
||||
records = records,
|
||||
recordsPredicate = null,
|
||||
section = section,
|
||||
startIndex = startIndex,
|
||||
endIndex = endIndex,
|
||||
recordMapper = {
|
||||
val recipient = contactSearchPagedDataSourceRepository.getRecipientFromRecipientCursor(it)
|
||||
val groupsInCommon = contactSearchPagedDataSourceRepository.getGroupsInCommon(recipient)
|
||||
ContactSearchData.KnownRecipient(section.sectionKey, recipient, groupsInCommon = groupsInCommon)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R> createResultsCollection(
|
||||
section: ContactSearchConfiguration.Section,
|
||||
records: ContactSearchIterator<R>,
|
||||
|
||||
@@ -48,6 +48,10 @@ open class ContactSearchPagedDataSourceRepository(
|
||||
return contactRepository.queryNonGroupContacts(query ?: "", includeSelf)
|
||||
}
|
||||
|
||||
open fun queryGroupMemberContacts(query: String?): Cursor? {
|
||||
return contactRepository.queryGroupMemberContacts(query ?: "")
|
||||
}
|
||||
|
||||
open fun getGroupSearchIterator(
|
||||
section: ContactSearchConfiguration.Section.Groups,
|
||||
query: String?
|
||||
@@ -95,6 +99,20 @@ open class ContactSearchPagedDataSourceRepository(
|
||||
return Recipient.resolved(RecipientId.from(CursorUtil.requireLong(cursor, ContactRepository.ID_COLUMN)))
|
||||
}
|
||||
|
||||
open fun getGroupsInCommon(recipient: Recipient): GroupsInCommon {
|
||||
val groupsInCommon = SignalDatabase.groups.getPushGroupsContainingMember(recipient.id)
|
||||
val groupRecipientIds = groupsInCommon.take(2).map { it.recipientId }
|
||||
val names = Recipient.resolvedList(groupRecipientIds)
|
||||
.map { it.getDisplayName(context) }
|
||||
.sorted()
|
||||
|
||||
return GroupsInCommon(groupsInCommon.size, names)
|
||||
}
|
||||
|
||||
open fun hasGroupsInCommon(recipient: Recipient): Boolean {
|
||||
return SignalDatabase.groups.getPushGroupsContainingMember(recipient.id).isNotEmpty()
|
||||
}
|
||||
|
||||
open fun getRecipientFromGroupRecord(groupRecord: GroupRecord): Recipient {
|
||||
return Recipient.resolved(groupRecord.recipientId)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.thoughtcrime.securesms.contacts.paged
|
||||
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* Groups in common helper class
|
||||
*/
|
||||
data class GroupsInCommon(
|
||||
private val total: Int,
|
||||
private val names: List<String>
|
||||
) {
|
||||
fun toDisplayText(context: Context): String {
|
||||
return when (total) {
|
||||
1 -> context.getString(R.string.MessageRequestProfileView_member_of_one_group, names[0])
|
||||
2 -> context.getString(R.string.MessageRequestProfileView_member_of_two_groups, names[0], names[1])
|
||||
else -> context.getString(
|
||||
R.string.MessageRequestProfileView_member_of_many_groups, names[0], names[1],
|
||||
context.resources.getQuantityString(R.plurals.MessageRequestProfileView_member_of_d_additional_groups, total - 2, total - 2)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user