mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Release chat folders to internal users.
This commit is contained in:
committed by
Greyson Parrelli
parent
e5c122d972
commit
c4fc32988c
@@ -20,9 +20,9 @@ import org.thoughtcrime.securesms.util.rx.RxStore
|
||||
*/
|
||||
class ContactChipViewModel : ViewModel() {
|
||||
|
||||
private val store = RxStore(emptyList<SelectedContacts.Model>())
|
||||
private val store = RxStore(emptyList<SelectedContacts.Model<*>>())
|
||||
|
||||
val state: Flowable<List<SelectedContacts.Model>> = store.stateFlowable
|
||||
val state: Flowable<List<SelectedContacts.Model<*>>> = store.stateFlowable
|
||||
.distinctUntilChanged()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
||||
@@ -39,20 +39,27 @@ class ContactChipViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
fun add(selectedContact: SelectedContact) {
|
||||
disposables += getOrCreateRecipientId(selectedContact).map { Recipient.resolved(it) }.observeOn(Schedulers.io()).subscribe { recipient ->
|
||||
store.update { it + SelectedContacts.Model(selectedContact, recipient) }
|
||||
disposableMap[recipient.id]?.dispose()
|
||||
disposableMap[recipient.id] = store.update(recipient.live().observable().toFlowable(BackpressureStrategy.LATEST)) { changedRecipient, state ->
|
||||
val index = state.indexOfFirst { it.selectedContact.matches(selectedContact) }
|
||||
when {
|
||||
index == 0 -> {
|
||||
listOf(SelectedContacts.Model(selectedContact, changedRecipient)) + state.drop(index + 1)
|
||||
}
|
||||
index > 0 -> {
|
||||
state.take(index) + SelectedContacts.Model(selectedContact, changedRecipient) + state.drop(index + 1)
|
||||
}
|
||||
else -> {
|
||||
state
|
||||
if (selectedContact.hasChatType()) {
|
||||
store.update { it + SelectedContacts.ChatTypeModel(selectedContact) }
|
||||
} else {
|
||||
disposables += getOrCreateRecipientId(selectedContact).map { Recipient.resolved(it) }.observeOn(Schedulers.io()).subscribe { recipient ->
|
||||
store.update { it + SelectedContacts.RecipientModel(selectedContact, recipient) }
|
||||
disposableMap[recipient.id]?.dispose()
|
||||
disposableMap[recipient.id] = store.update(recipient.live().observable().toFlowable(BackpressureStrategy.LATEST)) { changedRecipient, state ->
|
||||
val index = state.indexOfFirst { it.selectedContact.matches(selectedContact) }
|
||||
|
||||
when {
|
||||
index == 0 -> {
|
||||
listOf(SelectedContacts.RecipientModel(selectedContact, changedRecipient)) + state.drop(index + 1)
|
||||
}
|
||||
|
||||
index > 0 -> {
|
||||
state.take(index) + SelectedContacts.RecipientModel(selectedContact, changedRecipient) + state.drop(index + 1)
|
||||
}
|
||||
|
||||
else -> {
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.paged.ChatType;
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration;
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@@ -19,23 +20,29 @@ public final class SelectedContact {
|
||||
private final RecipientId recipientId;
|
||||
private final String number;
|
||||
private final String username;
|
||||
private final ChatType chatType;
|
||||
|
||||
public static @NonNull SelectedContact forPhone(@Nullable RecipientId recipientId, @NonNull String number) {
|
||||
return new SelectedContact(recipientId, number, null);
|
||||
return new SelectedContact(recipientId, number, null, null);
|
||||
}
|
||||
|
||||
public static @NonNull SelectedContact forUsername(@Nullable RecipientId recipientId, @NonNull String username) {
|
||||
return new SelectedContact(recipientId, null, username);
|
||||
return new SelectedContact(recipientId, null, username, null);
|
||||
}
|
||||
|
||||
public static @NonNull SelectedContact forChatType(@NonNull ChatType chatType) {
|
||||
return new SelectedContact(null, null, null, chatType);
|
||||
}
|
||||
|
||||
public static @NonNull SelectedContact forRecipientId(@NonNull RecipientId recipientId) {
|
||||
return new SelectedContact(recipientId, null, null);
|
||||
return new SelectedContact(recipientId, null, null, null);
|
||||
}
|
||||
|
||||
private SelectedContact(@Nullable RecipientId recipientId, @Nullable String number, @Nullable String username) {
|
||||
private SelectedContact(@Nullable RecipientId recipientId, @Nullable String number, @Nullable String username, @Nullable ChatType chatType) {
|
||||
this.recipientId = recipientId;
|
||||
this.number = number;
|
||||
this.username = username;
|
||||
this.chatType = chatType;
|
||||
}
|
||||
|
||||
public @NonNull RecipientId getOrCreateRecipientId(@NonNull Context context) {
|
||||
@@ -60,6 +67,14 @@ public final class SelectedContact {
|
||||
return username != null;
|
||||
}
|
||||
|
||||
public boolean hasChatType() {
|
||||
return chatType != null;
|
||||
}
|
||||
|
||||
public ChatType getChatType() {
|
||||
return chatType;
|
||||
}
|
||||
|
||||
public @NonNull ContactSearchKey toContactSearchKey() {
|
||||
if (recipientId != null) {
|
||||
return new ContactSearchKey.RecipientSearchKey(recipientId, false);
|
||||
@@ -67,6 +82,8 @@ public final class SelectedContact {
|
||||
return new ContactSearchKey.UnknownRecipientKey(ContactSearchConfiguration.SectionKey.PHONE_NUMBER, number);
|
||||
} else if (username != null) {
|
||||
return new ContactSearchKey.UnknownRecipientKey(ContactSearchConfiguration.SectionKey.USERNAME, username);
|
||||
} else if (chatType != null) {
|
||||
return new ContactSearchKey.ChatTypeSearchKey(chatType);
|
||||
} else {
|
||||
throw new IllegalStateException("Nothing to map!");
|
||||
}
|
||||
@@ -86,6 +103,7 @@ public final class SelectedContact {
|
||||
}
|
||||
|
||||
return number != null && number .equals(other.number) ||
|
||||
username != null && username.equals(other.username);
|
||||
username != null && username.equals(other.username) ||
|
||||
chatType != null && chatType.equals(other.chatType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package org.thoughtcrime.securesms.contacts
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.View
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.bumptech.glide.Glide
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.contacts.paged.ChatType
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
@@ -11,25 +15,28 @@ import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
|
||||
|
||||
object SelectedContacts {
|
||||
@JvmStatic
|
||||
fun register(adapter: MappingAdapter, onCloseIconClicked: (Model) -> Unit) {
|
||||
adapter.registerFactory(Model::class.java, LayoutFactory({ ViewHolder(it, onCloseIconClicked) }, R.layout.contact_selection_list_chip))
|
||||
fun register(adapter: MappingAdapter, onCloseIconClicked: (Model<*>) -> Unit) {
|
||||
adapter.registerFactory(RecipientModel::class.java, LayoutFactory({ RecipientViewHolder(it, onCloseIconClicked) }, R.layout.contact_selection_list_chip))
|
||||
adapter.registerFactory(ChatTypeModel::class.java, LayoutFactory({ ChatTypeViewHolder(it, onCloseIconClicked) }, R.layout.contact_selection_list_chip))
|
||||
}
|
||||
|
||||
class Model(val selectedContact: SelectedContact, val recipient: Recipient) : MappingModel<Model> {
|
||||
override fun areItemsTheSame(newItem: Model): Boolean {
|
||||
sealed class Model<T : Any>(val selectedContact: SelectedContact) : MappingModel<T>
|
||||
|
||||
class RecipientModel(selectedContact: SelectedContact, val recipient: Recipient) : Model<RecipientModel>(selectedContact = selectedContact) {
|
||||
override fun areItemsTheSame(newItem: RecipientModel): Boolean {
|
||||
return newItem.selectedContact.matches(selectedContact) && recipient == newItem.recipient
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(newItem: Model): Boolean {
|
||||
override fun areContentsTheSame(newItem: RecipientModel): Boolean {
|
||||
return areItemsTheSame(newItem) && recipient.hasSameContent(newItem.recipient)
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewHolder(itemView: View, private val onCloseIconClicked: (Model) -> Unit) : MappingViewHolder<Model>(itemView) {
|
||||
private class RecipientViewHolder(itemView: View, private val onCloseIconClicked: (RecipientModel) -> Unit) : MappingViewHolder<RecipientModel>(itemView) {
|
||||
|
||||
private val chip: ContactChip = itemView.findViewById(R.id.contact_chip)
|
||||
|
||||
override fun bind(model: Model) {
|
||||
override fun bind(model: RecipientModel) {
|
||||
chip.text = model.recipient.getShortDisplayName(context)
|
||||
chip.setContact(model.selectedContact)
|
||||
chip.isCloseIconVisible = true
|
||||
@@ -39,4 +46,36 @@ object SelectedContacts {
|
||||
chip.setAvatar(Glide.with(itemView), model.recipient, null)
|
||||
}
|
||||
}
|
||||
|
||||
class ChatTypeModel(selectedContact: SelectedContact) : Model<ChatTypeModel>(selectedContact = selectedContact) {
|
||||
override fun areItemsTheSame(newItem: ChatTypeModel): Boolean {
|
||||
return newItem.selectedContact.matches(selectedContact) && newItem.selectedContact.chatType == selectedContact.chatType
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(newItem: ChatTypeModel): Boolean {
|
||||
return areItemsTheSame(newItem)
|
||||
}
|
||||
}
|
||||
|
||||
private class ChatTypeViewHolder(itemView: View, private val onCloseIconClicked: (ChatTypeModel) -> Unit) : MappingViewHolder<ChatTypeModel>(itemView) {
|
||||
|
||||
private val chip: ContactChip = itemView.findViewById(R.id.contact_chip)
|
||||
|
||||
override fun bind(model: ChatTypeModel) {
|
||||
if (model.selectedContact.chatType == ChatType.INDIVIDUAL) {
|
||||
chip.text = context.getString(R.string.ChatFoldersFragment__one_on_one_chats)
|
||||
chip.chipIcon = AppCompatResources.getDrawable(context, R.drawable.symbol_person_light_24)
|
||||
chip.chipIconTint = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.signal_colorOnSurface))
|
||||
} else {
|
||||
chip.text = context.getString(R.string.ChatFoldersFragment__groups)
|
||||
chip.chipIcon = AppCompatResources.getDrawable(context, R.drawable.symbol_group_light_20)
|
||||
chip.chipIconTint = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.signal_colorOnSurface))
|
||||
}
|
||||
chip.setContact(model.selectedContact)
|
||||
chip.isCloseIconVisible = true
|
||||
chip.setOnCloseIconClickListener {
|
||||
onCloseIconClicked(model)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.thoughtcrime.securesms.contacts.paged
|
||||
|
||||
/**
|
||||
* Enum class that represents the different chat types a chat folder can have
|
||||
*/
|
||||
enum class ChatType {
|
||||
INDIVIDUAL,
|
||||
GROUPS
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.text.SpannableStringBuilder
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckBox
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -57,6 +58,7 @@ open class ContactSearchAdapter(
|
||||
registerKnownRecipientItems(this, fixedContacts, displayOptions, onClickCallbacks::onKnownRecipientClicked, longClickCallbacks::onKnownRecipientLongClick, callButtonClickCallbacks)
|
||||
registerHeaders(this)
|
||||
registerExpands(this, onClickCallbacks::onExpandClicked)
|
||||
registerChatTypeItems(this, onClickCallbacks::onChatTypeClicked)
|
||||
registerFactory(UnknownRecipientModel::class.java, LayoutFactory({ UnknownRecipientViewHolder(it, onClickCallbacks::onUnknownRecipientClicked, displayOptions.displayCheckBox) }, R.layout.contact_search_unknown_item))
|
||||
}
|
||||
|
||||
@@ -117,6 +119,13 @@ open class ContactSearchAdapter(
|
||||
)
|
||||
}
|
||||
|
||||
fun registerChatTypeItems(mappingAdapter: MappingAdapter, chatTypeRowListener: OnClickedCallback<ContactSearchData.ChatTypeRow>) {
|
||||
mappingAdapter.registerFactory(
|
||||
ChatTypeModel::class.java,
|
||||
LayoutFactory({ ChatTypeViewHolder(it, chatTypeRowListener) }, R.layout.contact_search_chat_type_item)
|
||||
)
|
||||
}
|
||||
|
||||
fun toMappingModelList(contactSearchData: List<ContactSearchData?>, selection: Set<ContactSearchKey>, arbitraryRepository: ArbitraryRepository?): MappingModelList {
|
||||
return MappingModelList(
|
||||
contactSearchData.filterNotNull().map {
|
||||
@@ -132,6 +141,7 @@ open class ContactSearchAdapter(
|
||||
is ContactSearchData.Empty -> EmptyModel(it)
|
||||
is ContactSearchData.GroupWithMembers -> GroupWithMembersModel(it)
|
||||
is ContactSearchData.UnknownRecipient -> UnknownRecipientModel(it)
|
||||
is ContactSearchData.ChatTypeRow -> ChatTypeModel(it, selection.contains(it.contactSearchKey))
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -675,6 +685,7 @@ open class ContactSearchAdapter(
|
||||
ContactSearchConfiguration.SectionKey.MESSAGES -> R.string.ContactsCursorLoader__messages
|
||||
ContactSearchConfiguration.SectionKey.GROUPS_WITH_MEMBERS -> R.string.ContactsCursorLoader_group_members
|
||||
ContactSearchConfiguration.SectionKey.CONTACTS_WITHOUT_THREADS -> R.string.ContactsCursorLoader_contacts
|
||||
ContactSearchConfiguration.SectionKey.CHAT_TYPES -> R.string.ContactsCursorLoader__chat_types
|
||||
else -> error("This section does not support HEADER")
|
||||
}
|
||||
)
|
||||
@@ -712,6 +723,42 @@ open class ContactSearchAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping Model for chat types.
|
||||
*/
|
||||
class ChatTypeModel(val data: ContactSearchData.ChatTypeRow, val isSelected: Boolean) : MappingModel<ChatTypeModel> {
|
||||
override fun areItemsTheSame(newItem: ChatTypeModel): Boolean = data == newItem.data
|
||||
override fun areContentsTheSame(newItem: ChatTypeModel): Boolean = data == newItem.data && isSelected == newItem.isSelected
|
||||
}
|
||||
|
||||
/**
|
||||
* View Holder for chat types
|
||||
*/
|
||||
private class ChatTypeViewHolder(
|
||||
itemView: View,
|
||||
val onClick: OnClickedCallback<ContactSearchData.ChatTypeRow>
|
||||
) : MappingViewHolder<ChatTypeModel>(itemView) {
|
||||
|
||||
val image: ImageView = itemView.findViewById(R.id.image)
|
||||
val name: TextView = itemView.findViewById(R.id.name)
|
||||
val checkbox: CheckBox = itemView.findViewById(R.id.check_box)
|
||||
|
||||
override fun bind(model: ChatTypeModel) {
|
||||
itemView.setOnClickListener { onClick.onClicked(itemView, model.data, model.isSelected) }
|
||||
|
||||
image.setImageResource(model.data.imageResId)
|
||||
|
||||
if (model.data.chatType == ChatType.INDIVIDUAL) {
|
||||
name.text = context.getString(R.string.ChatFoldersFragment__one_on_one_chats)
|
||||
}
|
||||
if (model.data.chatType == ChatType.GROUPS) {
|
||||
name.text = context.getString(R.string.ChatFoldersFragment__groups)
|
||||
}
|
||||
|
||||
checkbox.isChecked = model.isSelected
|
||||
}
|
||||
}
|
||||
|
||||
private class IsSelfComparator : Comparator<Recipient> {
|
||||
override fun compare(lhs: Recipient?, rhs: Recipient?): Int {
|
||||
val isLeftSelf = lhs?.isSelf == true
|
||||
@@ -764,6 +811,7 @@ open class ContactSearchAdapter(
|
||||
fun onUnknownRecipientClicked(view: View, unknownRecipient: ContactSearchData.UnknownRecipient, isSelected: Boolean) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
fun onChatTypeClicked(view: View, chatTypeRow: ContactSearchData.ChatTypeRow, isSelected: Boolean)
|
||||
}
|
||||
|
||||
interface CallButtonClickCallbacks {
|
||||
|
||||
@@ -193,6 +193,18 @@ class ContactSearchConfiguration private constructor(
|
||||
override val includeHeader: Boolean = false
|
||||
override val expandConfig: ExpandConfig? = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat types that are displayed when creating a chat folder.
|
||||
*
|
||||
* Key: [ContactSearchKey.ChatType]
|
||||
* Data: [ContactSearchData.ChatTypeRow]
|
||||
* Model: [ContactSearchAdapter.ChatTypeModel]
|
||||
*/
|
||||
data class ChatTypes(
|
||||
override val includeHeader: Boolean = true,
|
||||
override val expandConfig: ExpandConfig? = null
|
||||
) : Section(SectionKey.CHAT_TYPES)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,6 +246,11 @@ class ContactSearchConfiguration private constructor(
|
||||
*/
|
||||
CONTACTS_WITHOUT_THREADS,
|
||||
|
||||
/**
|
||||
* Chat types (ie unreads, 1:1, groups) that are used to customize folders
|
||||
*/
|
||||
CHAT_TYPES,
|
||||
|
||||
/**
|
||||
* Arbitrary row (think new group button, username row, etc)
|
||||
*/
|
||||
|
||||
@@ -69,6 +69,14 @@ sealed class ContactSearchData(val contactSearchKey: ContactSearchKey) {
|
||||
val action: HeaderAction?
|
||||
) : ContactSearchData(ContactSearchKey.Header(sectionKey))
|
||||
|
||||
/**
|
||||
* A row containing a chat type (filters that can be applied to a chat folders)
|
||||
*/
|
||||
class ChatTypeRow(
|
||||
val imageResId: Int,
|
||||
val chatType: ChatType
|
||||
) : ContactSearchData(ContactSearchKey.ChatTypeSearchKey(chatType))
|
||||
|
||||
/**
|
||||
* A row which the user can click to view all entries for a given section.
|
||||
*/
|
||||
|
||||
@@ -76,5 +76,14 @@ sealed class ContactSearchKey {
|
||||
*/
|
||||
data class Message(val messageId: Long) : ContactSearchKey()
|
||||
|
||||
/**
|
||||
* Search key for a ChatType
|
||||
*/
|
||||
data class ChatTypeSearchKey(val chatType: ChatType) : ContactSearchKey() {
|
||||
override fun requireSelectedContact(): SelectedContact {
|
||||
return SelectedContact.forChatType(chatType)
|
||||
}
|
||||
}
|
||||
|
||||
object Empty : ContactSearchKey()
|
||||
}
|
||||
|
||||
@@ -87,6 +87,11 @@ class ContactSearchMediator(
|
||||
Log.d(TAG, "onExpandClicked()")
|
||||
viewModel.expandSection(expand.sectionKey)
|
||||
}
|
||||
|
||||
override fun onChatTypeClicked(view: View, chatTypeRow: ContactSearchData.ChatTypeRow, isSelected: Boolean) {
|
||||
Log.d(TAG, "onChatTypeClicked() chatType $chatTypeRow")
|
||||
toggleChatTypeSelection(view, chatTypeRow, isSelected)
|
||||
}
|
||||
},
|
||||
longClickCallbacks = ContactSearchAdapter.LongClickCallbacksAdapter(),
|
||||
storyContextMenuCallbacks = StoryContextMenuCallbacks(),
|
||||
@@ -188,6 +193,16 @@ class ContactSearchMediator(
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleChatTypeSelection(view: View, contactSearchData: ContactSearchData, isSelected: Boolean) {
|
||||
return if (isSelected) {
|
||||
Log.d(TAG, "toggleSelection(OFF) ${contactSearchData.contactSearchKey}")
|
||||
viewModel.setKeysNotSelected(setOf(contactSearchData.contactSearchKey))
|
||||
} else {
|
||||
Log.d(TAG, "toggleSelection(ON) ${contactSearchData.contactSearchKey}")
|
||||
viewModel.setKeysSelected(callbacks.onBeforeContactsSelected(view, setOf(contactSearchData.contactSearchKey)))
|
||||
}
|
||||
}
|
||||
|
||||
private inner class StoryContextMenuCallbacks : ContactSearchAdapter.StoryContextMenuCallbacks {
|
||||
override fun onOpenStorySettings(story: ContactSearchData.Story) {
|
||||
if (story.recipient.isMyStory) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.contacts.paged
|
||||
import android.database.Cursor
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.paging.PagedDataSource
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.contacts.ContactRepository
|
||||
import org.thoughtcrime.securesms.contacts.paged.collections.ContactSearchCollection
|
||||
import org.thoughtcrime.securesms.contacts.paged.collections.ContactSearchIterator
|
||||
@@ -142,6 +143,7 @@ class ContactSearchPagedDataSource(
|
||||
is ContactSearchConfiguration.Section.PhoneNumber -> if (isPossiblyPhoneNumber(query)) 1 else 0
|
||||
is ContactSearchConfiguration.Section.Username -> if (isPossiblyUsername(query)) 1 else 0
|
||||
is ContactSearchConfiguration.Section.Empty -> 1
|
||||
is ContactSearchConfiguration.Section.ChatTypes -> getChatTypesData(section).size
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +183,7 @@ class ContactSearchPagedDataSource(
|
||||
is ContactSearchConfiguration.Section.PhoneNumber -> getPossiblePhoneNumber(section, query)
|
||||
is ContactSearchConfiguration.Section.Username -> getPossibleUsername(section, query)
|
||||
is ContactSearchConfiguration.Section.Empty -> listOf(ContactSearchData.Empty(query))
|
||||
is ContactSearchConfiguration.Section.ChatTypes -> getChatTypesData(section)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +351,22 @@ class ContactSearchPagedDataSource(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [michelle]: Replace hardcoding chat types after building db
|
||||
private fun getChatTypesData(section: ContactSearchConfiguration.Section.ChatTypes): List<ContactSearchData> {
|
||||
val data = mutableListOf<ContactSearchData>()
|
||||
|
||||
if (section.includeHeader) {
|
||||
data.add(ContactSearchData.Header(section.sectionKey, section.headerAction))
|
||||
}
|
||||
data.addAll(
|
||||
listOf(
|
||||
ContactSearchData.ChatTypeRow(R.drawable.symbol_person_light_24, ChatType.INDIVIDUAL),
|
||||
ContactSearchData.ChatTypeRow(R.drawable.symbol_group_light_20, ChatType.GROUPS)
|
||||
)
|
||||
)
|
||||
return data
|
||||
}
|
||||
|
||||
private fun getContactsWithoutThreadsContactData(section: ContactSearchConfiguration.Section.ContactsWithoutThreads, query: String?, startIndex: Int, endIndex: Int): List<ContactSearchData> {
|
||||
return getContactsWithoutThreadsIterator(query).use { records ->
|
||||
readContactData(
|
||||
|
||||
@@ -21,6 +21,7 @@ class ContactSearchRepository {
|
||||
val isSelectable = when (it) {
|
||||
is ContactSearchKey.RecipientSearchKey -> canSelectRecipient(it.recipientId)
|
||||
is ContactSearchKey.UnknownRecipientKey -> it.sectionKey == ContactSearchConfiguration.SectionKey.PHONE_NUMBER
|
||||
is ContactSearchKey.ChatTypeSearchKey -> true
|
||||
else -> false
|
||||
}
|
||||
ContactSearchSelectionResult(it, isSelectable)
|
||||
|
||||
Reference in New Issue
Block a user