Remove cluster of orphaned code around CameraContactSelectionViewController.

This commit is contained in:
andrew-signal
2026-05-22 12:49:52 -04:00
committed by Michelle Tang
parent faadc9854f
commit 71967b278e
19 changed files with 0 additions and 1072 deletions
@@ -1,253 +0,0 @@
package org.thoughtcrime.securesms.mediasend;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.RequestManager;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.adapter.SectionedRecyclerViewAdapter;
import org.thoughtcrime.securesms.util.adapter.StableIdGenerator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class CameraContactAdapter extends SectionedRecyclerViewAdapter<String, CameraContactAdapter.ContactSection> {
private static final int TYPE_INVITE = 1337;
private static final long ID_INVITE = Long.MAX_VALUE;
private static final String TAG_RECENT = "recent";
private static final String TAG_ALL = "all";
private static final String TAG_GROUPS = "groups";
private final RequestManager requestManager;
private final Set<Recipient> selected;
private final CameraContactListener cameraContactListener;
private final List<ContactSection> sections = new ArrayList<ContactSection>(3) {{
ContactSection recentContacts = new ContactSection(TAG_RECENT, R.string.CameraContacts_recent_contacts, Collections.emptyList(), 0);
ContactSection allContacts = new ContactSection(TAG_ALL, R.string.CameraContacts_signal_contacts, Collections.emptyList(), recentContacts.size());
ContactSection groups = new ContactSection(TAG_GROUPS, R.string.CameraContacts_signal_groups, Collections.emptyList(), recentContacts.size() + allContacts.size());
add(recentContacts);
add(allContacts);
add(groups);
}};
CameraContactAdapter(@NonNull RequestManager requestManager, @NonNull CameraContactListener listener) {
this.requestManager = requestManager;
this.selected = new HashSet<>();
this.cameraContactListener = listener;
}
@Override
protected @NonNull List<ContactSection> getSections() {
return sections;
}
@Override
public long getItemId(int globalPosition) {
if (isInvitePosition(globalPosition)) {
return ID_INVITE;
} else {
return super.getItemId(globalPosition);
}
}
@Override
public int getItemViewType(int globalPosition) {
if (isInvitePosition(globalPosition)) {
return TYPE_INVITE;
} else {
return super.getItemViewType(globalPosition);
}
}
@Override
public @NonNull RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
if (viewType == TYPE_INVITE) {
return new InviteViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.camera_contact_invite_item, viewGroup, false));
} else {
return super.onCreateViewHolder(viewGroup, viewType);
}
}
@Override
protected @NonNull RecyclerView.ViewHolder createHeaderViewHolder(@NonNull ViewGroup parent) {
return new HeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.camera_contact_header_item, parent, false));
}
@Override
protected @NonNull RecyclerView.ViewHolder createContentViewHolder(@NonNull ViewGroup parent) {
return new ContactViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.camera_contact_contact_item, parent, false));
}
@Override
protected @Nullable RecyclerView.ViewHolder createEmptyViewHolder(@NonNull ViewGroup viewGroup) {
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int globalPosition) {
if (isInvitePosition(globalPosition)) {
((InviteViewHolder) holder).bind(cameraContactListener);
} else {
super.onBindViewHolder(holder, globalPosition);
}
}
@Override
protected void bindViewHolder(@NonNull RecyclerView.ViewHolder holder, @NonNull ContactSection section, int localPosition) {
section.bind(holder, localPosition, selected, requestManager, cameraContactListener);
}
@Override
public int getItemCount() {
return super.getItemCount() + 1;
}
public void setContacts(@NonNull CameraContacts contacts, @NonNull Collection<Recipient> selected) {
ContactSection recentContacts = new ContactSection(TAG_RECENT, R.string.CameraContacts_recent_contacts, contacts.getRecents(), 0);
ContactSection allContacts = new ContactSection(TAG_ALL, R.string.CameraContacts_signal_contacts, contacts.getContacts(), recentContacts.size());
ContactSection groups = new ContactSection(TAG_GROUPS, R.string.CameraContacts_signal_groups, contacts.getGroups(), recentContacts.size() + allContacts.size());
sections.clear();
sections.add(recentContacts);
sections.add(allContacts);
sections.add(groups);
this.selected.clear();
this.selected.addAll(selected);
notifyDataSetChanged();
}
private boolean isInvitePosition(int globalPosition) {
return globalPosition == getItemCount() - 1;
}
public static class ContactSection extends SectionedRecyclerViewAdapter.Section<String> {
private final String tag;
private final int titleResId;
private final List<Recipient> recipients;
public ContactSection(@NonNull String tag, @StringRes int titleResId, @NonNull List<Recipient> recipients, int offset) {
super(offset);
this.tag = tag;
this.titleResId = titleResId;
this.recipients = recipients;
}
@Override
public boolean hasEmptyState() {
return false;
}
@Override
public int getContentSize() {
return recipients.size();
}
@Override
public long getItemId(@NonNull StableIdGenerator<String> idGenerator, int globalPosition) {
int localPosition = getLocalPosition(globalPosition);
if (localPosition == 0) {
return idGenerator.getId(tag);
} else {
return idGenerator.getId(recipients.get(localPosition - 1).getId().serialize());
}
}
void bind(@NonNull RecyclerView.ViewHolder viewHolder,
int localPosition,
@NonNull Set<Recipient> selected,
@NonNull RequestManager requestManager,
@NonNull CameraContactListener cameraContactListener)
{
if (localPosition == 0) {
((HeaderViewHolder) viewHolder).bind(titleResId);
} else {
Recipient recipient = recipients.get(localPosition - 1);
((ContactViewHolder) viewHolder).bind(recipient, selected.contains(recipient), requestManager, cameraContactListener);
}
}
}
private static class HeaderViewHolder extends RecyclerView.ViewHolder {
private final TextView title;
HeaderViewHolder(@NonNull View itemView) {
super(itemView);
this.title = itemView.findViewById(R.id.camera_contact_header);
}
void bind(@StringRes int titleResId) {
this.title.setText(titleResId);
}
}
private static class ContactViewHolder extends RecyclerView.ViewHolder {
private final AvatarImageView avatar;
private final FromTextView name;
private final CheckBox checkbox;
ContactViewHolder(@NonNull View itemView) {
super(itemView);
this.avatar = itemView.findViewById(R.id.camera_contact_item_avatar);
this.name = itemView.findViewById(R.id.camera_contact_item_name);
this.checkbox = itemView.findViewById(R.id.camera_contact_item_checkbox);
}
void bind(@NonNull Recipient recipient,
boolean selected,
@NonNull RequestManager requestManager,
@NonNull CameraContactListener listener)
{
avatar.setAvatar(requestManager, recipient, false);
name.setText(recipient);
itemView.setOnClickListener(v -> listener.onContactClicked(recipient));
checkbox.setChecked(selected);
}
}
private static class InviteViewHolder extends RecyclerView.ViewHolder {
private final View inviteButton;
public InviteViewHolder(@NonNull View itemView) {
super(itemView);
inviteButton = itemView.findViewById(R.id.camera_contact_invite);
}
void bind(@NonNull CameraContactListener listener) {
inviteButton.setOnClickListener(v -> listener.onInviteContactsClicked());
}
}
interface CameraContactListener {
void onContactClicked(@NonNull Recipient recipient);
void onInviteContactsClicked();
}
}
@@ -1,66 +0,0 @@
package org.thoughtcrime.securesms.mediasend;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.adapter.StableIdGenerator;
import java.util.ArrayList;
import java.util.List;
class CameraContactSelectionAdapter extends RecyclerView.Adapter<CameraContactSelectionAdapter.RecipientViewHolder> {
private final List<Recipient> recipients = new ArrayList<>();
private final StableIdGenerator<String> idGenerator = new StableIdGenerator<>();
CameraContactSelectionAdapter() {
setHasStableIds(true);
}
@Override
public long getItemId(int position) {
return idGenerator.getId(recipients.get(position).getId().serialize());
}
@Override
public @NonNull RecipientViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RecipientViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.camera_contact_selection_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecipientViewHolder holder, int position) {
holder.bind(recipients.get(position), position == recipients.size() - 1);
}
@Override
public int getItemCount() {
return recipients.size();
}
void setRecipients(@NonNull List<Recipient> recipients) {
this.recipients.clear();
this.recipients.addAll(recipients);
notifyDataSetChanged();
}
static class RecipientViewHolder extends RecyclerView.ViewHolder {
private final FromTextView name;
RecipientViewHolder(View itemView) {
super(itemView);
name = (FromTextView) itemView;
}
void bind(@NonNull Recipient recipient, boolean isLast) {
name.setText(recipient, isLast ? null : ",");
}
}
}
@@ -1,192 +0,0 @@
package org.thoughtcrime.securesms.mediasend;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.Group;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import org.signal.core.ui.logging.LoggingFragment;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.signal.core.ui.util.ThemeUtil;
import java.util.List;
/**
* Fragment that selects Signal contacts. Intended to be used in the camera-first capture flow.
*/
public class CameraContactSelectionFragment extends LoggingFragment implements CameraContactAdapter.CameraContactListener {
private Controller controller;
private CameraContactSelectionViewModel contactViewModel;
private RecyclerView contactList;
private CameraContactAdapter contactAdapter;
private RecyclerView selectionList;
private CameraContactSelectionAdapter selectionAdapter;
private Toolbar toolbar;
private View sendButton;
private Group selectionFooterGroup;
private ViewGroup cameraContactsEmpty;
private View inviteButton;
public static Fragment newInstance() {
return new CameraContactSelectionFragment();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
CameraContactSelectionViewModel.Factory factory = new CameraContactSelectionViewModel.Factory(new CameraContactsRepository(requireContext()));
this.contactViewModel = new ViewModelProvider(requireActivity(), factory).get(CameraContactSelectionViewModel.class);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (!(getActivity() instanceof Controller)) {
throw new IllegalStateException("Parent activity must implement controller interface.");
}
controller = (Controller) getActivity();
}
@Override
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
int theme = DynamicTheme.isDarkTheme(inflater.getContext()) ? R.style.TextSecure_DarkTheme
: R.style.TextSecure_LightTheme;
return ThemeUtil.getThemedInflater(inflater.getContext(), inflater, theme)
.inflate(R.layout.camera_contact_selection_fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
this.contactList = view.findViewById(R.id.camera_contacts_list);
this.selectionList = view.findViewById(R.id.camera_contacts_selected_list);
this.toolbar = view.findViewById(R.id.camera_contacts_toolbar);
this.sendButton = view.findViewById(R.id.camera_contacts_send_button);
this.selectionFooterGroup = view.findViewById(R.id.camera_contacts_footer_group);
this.cameraContactsEmpty = view.findViewById(R.id.camera_contacts_empty);
this.inviteButton = view.findViewById(R.id.camera_contacts_invite_button);
this.contactAdapter = new CameraContactAdapter(Glide.with(this), this);
this.selectionAdapter = new CameraContactSelectionAdapter();
contactList.setLayoutManager(new LinearLayoutManager(requireContext()));
contactList.setAdapter(contactAdapter);
selectionList.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
selectionList.setAdapter(selectionAdapter);
((AppCompatActivity) requireActivity()).setSupportActionBar(toolbar);
((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(v -> requireActivity().onBackPressed());
inviteButton.setOnClickListener(v -> onInviteContactsClicked());
initViewModel();
}
@Override
public void onPrepareOptionsMenu(@NonNull Menu menu) {
requireActivity().getMenuInflater().inflate(R.menu.camera_contacts, menu);
MenuItem searchViewItem = menu.findItem(R.id.menu_search);
SearchView searchView = (SearchView) searchViewItem.getActionView();
SearchView.OnQueryTextListener queryListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
contactViewModel.onQueryUpdated(query);
return true;
}
@Override
public boolean onQueryTextChange(String query) {
contactViewModel.onQueryUpdated(query);
return true;
}
};
searchViewItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
searchView.setOnQueryTextListener(queryListener);
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
searchView.setOnQueryTextListener(null);
contactViewModel.onSearchClosed();
return true;
}
});
}
@Override
public void onContactClicked(@NonNull Recipient recipient) {
contactViewModel.onContactClicked(recipient);
}
@Override
public void onInviteContactsClicked() {
startActivity(AppSettingsActivity.invite(requireContext()));
}
private void initViewModel() {
contactViewModel.getContacts().observe(getViewLifecycleOwner(), contactState -> {
if (contactState == null) return;
if (contactState.getContacts().isEmpty() && TextUtils.isEmpty(contactState.getQuery())) {
cameraContactsEmpty.setVisibility(View.VISIBLE);
contactList.setVisibility(View.GONE);
selectionFooterGroup.setVisibility(View.GONE);
} else {
cameraContactsEmpty.setVisibility(View.GONE);
contactList.setVisibility(View.VISIBLE);
sendButton.setOnClickListener(v -> controller.onCameraContactsSendClicked(contactState.getSelected()));
contactAdapter.setContacts(contactState.getContacts(), contactState.getSelected());
selectionAdapter.setRecipients(contactState.getSelected());
selectionFooterGroup.setVisibility(contactState.getSelected().isEmpty() ? View.GONE : View.VISIBLE);
}
});
contactViewModel.getError().observe(getViewLifecycleOwner(), error -> {
if (error == null) return;
if (error == CameraContactSelectionViewModel.Error.MAX_SELECTION) {
String message = getResources().getQuantityString(R.plurals.CameraContacts_you_can_share_with_a_maximum_of_n_conversations, CameraContactSelectionViewModel.MAX_SELECTION_COUNT, CameraContactSelectionViewModel.MAX_SELECTION_COUNT);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
}
});
}
public interface Controller {
void onCameraContactsSendClicked(@NonNull List<Recipient> recipients);
}
}
@@ -1,132 +0,0 @@
package org.thoughtcrime.securesms.mediasend;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import org.signal.core.util.ThreadUtil;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
class CameraContactSelectionViewModel extends ViewModel {
static final int MAX_SELECTION_COUNT = 16;
private final CameraContactsRepository repository;
private final MutableLiveData<ContactState> contacts;
private final SingleLiveEvent<Error> error;
private final Set<Recipient> selected;
private String currentQuery;
private CameraContactSelectionViewModel(@NonNull CameraContactsRepository repository) {
this.repository = repository;
this.contacts = new MutableLiveData<>();
this.error = new SingleLiveEvent<>();
this.selected = new LinkedHashSet<>();
repository.getCameraContacts(cameraContacts -> {
ThreadUtil.runOnMain(() -> {
contacts.postValue(new ContactState(cameraContacts, new ArrayList<>(selected), currentQuery));
});
});
}
LiveData<ContactState> getContacts() {
return contacts;
}
LiveData<Error> getError() {
return error;
}
void onSearchClosed() {
onQueryUpdated("");
}
void onQueryUpdated(String query) {
this.currentQuery = query;
repository.getCameraContacts(query, cameraContacts -> {
ThreadUtil.runOnMain(() -> {
contacts.postValue(new ContactState(cameraContacts, new ArrayList<>(selected), query));
});
});
}
void onRefresh() {
repository.getCameraContacts(cameraContacts -> {
ThreadUtil.runOnMain(() -> {
contacts.postValue(new ContactState(cameraContacts, new ArrayList<>(selected), currentQuery));
});
});
}
void onContactClicked(@NonNull Recipient recipient) {
if (selected.contains(recipient)) {
selected.remove(recipient);
} else if (selected.size() < MAX_SELECTION_COUNT) {
selected.add(recipient);
} else {
error.postValue(Error.MAX_SELECTION);
}
ContactState currentState = contacts.getValue();
if (currentState != null) {
contacts.setValue(new ContactState(currentState.getContacts(), new ArrayList<>(selected), currentQuery));
}
}
static class ContactState {
private final CameraContacts contacts;
private final List<Recipient> selected;
private final String query;
ContactState(@NonNull CameraContacts contacts, @NonNull List<Recipient> selected, @Nullable String query) {
this.contacts = contacts;
this.selected = selected;
this.query = query;
}
public CameraContacts getContacts() {
return contacts;
}
public List<Recipient> getSelected() {
return selected;
}
public @Nullable String getQuery() {
return query;
}
}
enum Error {
MAX_SELECTION
}
static class Factory extends ViewModelProvider.NewInstanceFactory {
private final CameraContactsRepository repository;
Factory(CameraContactsRepository repository) {
this.repository = repository;
}
@Override
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection ConstantConditions
return modelClass.cast(new CameraContactSelectionViewModel(repository));
}
}
}
@@ -1,39 +0,0 @@
package org.thoughtcrime.securesms.mediasend;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.List;
/**
* Represents the list of results to display in the {@link CameraContactSelectionFragment}.
*/
public class CameraContacts {
private final List<Recipient> recents;
private final List<Recipient> contacts;
private final List<Recipient> groups;
public CameraContacts(@NonNull List<Recipient> recents, @NonNull List<Recipient> contacts, @NonNull List<Recipient> groups) {
this.recents = recents;
this.contacts = contacts;
this.groups = groups;
}
public @NonNull List<Recipient> getRecents() {
return recents;
}
public @NonNull List<Recipient> getContacts() {
return contacts;
}
public @NonNull List<Recipient> getGroups() {
return groups;
}
public boolean isEmpty() {
return recents.isEmpty() && contacts.isEmpty() && groups.isEmpty();
}
}
@@ -1,138 +0,0 @@
package org.thoughtcrime.securesms.mediasend;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.ContactRepository;
import org.thoughtcrime.securesms.database.GroupTable;
import org.thoughtcrime.securesms.database.RecipientTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.ThreadTable;
import org.thoughtcrime.securesms.database.model.GroupRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* Handles retrieving the data to be shown in {@link CameraContactSelectionFragment}.
*/
class CameraContactsRepository {
private static final String TAG = Log.tag(CameraContactsRepository.class);
private static final int RECENT_MAX = 25;
private final Context context;
private final ThreadTable threadTable;
private final GroupTable groupDatabase;
private final RecipientTable recipientTable;
private final ContactRepository contactRepository;
private final Executor serialExecutor;
private final ExecutorService parallelExecutor;
CameraContactsRepository(@NonNull Context context) {
this.context = context.getApplicationContext();
this.threadTable = SignalDatabase.threads();
this.groupDatabase = SignalDatabase.groups();
this.recipientTable = SignalDatabase.recipients();
this.contactRepository = new ContactRepository(context.getString(R.string.note_to_self));
this.serialExecutor = SignalExecutors.SERIAL;
this.parallelExecutor = SignalExecutors.BOUNDED;
}
void getCameraContacts(@NonNull Callback<CameraContacts> callback) {
getCameraContacts("", callback);
}
void getCameraContacts(@NonNull String query, @NonNull Callback<CameraContacts> callback) {
serialExecutor.execute(() -> {
Future<List<Recipient>> recents = parallelExecutor.submit(() -> getRecents(query));
Future<List<Recipient>> contacts = parallelExecutor.submit(() -> getContacts(query));
Future<List<Recipient>> groups = parallelExecutor.submit(() -> getGroups(query));
try {
long startTime = System.currentTimeMillis();
CameraContacts result = new CameraContacts(recents.get(), contacts.get(), groups.get());
Log.d(TAG, "Total time: " + (System.currentTimeMillis() - startTime) + " ms");
callback.onComplete(result);
} catch (InterruptedException | ExecutionException e) {
Log.w(TAG, "Failed to perform queries.", e);
callback.onComplete(new CameraContacts(Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
}
});
}
@WorkerThread
private @NonNull List<Recipient> getRecents(@NonNull String query) {
if (!TextUtils.isEmpty(query)) {
return Collections.emptyList();
}
List<Recipient> recipients = new ArrayList<>(RECENT_MAX);
try (ThreadTable.Reader threadReader = threadTable.readerFor(threadTable.getRecentPushConversationList(RECENT_MAX))) {
ThreadRecord threadRecord;
while ((threadRecord = threadReader.getNext()) != null) {
recipients.add(threadRecord.getRecipient().resolve());
}
}
return recipients;
}
@WorkerThread
private @NonNull List<Recipient> getContacts(@NonNull String query) {
List<Recipient> recipients = new ArrayList<>();
try (Cursor cursor = contactRepository.querySignalContacts(query)) {
while (cursor.moveToNext()) {
RecipientId id = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ContactRepository.ID_COLUMN)));
Recipient recipient = Recipient.resolved(id);
recipients.add(recipient);
}
}
return recipients;
}
@WorkerThread
private @NonNull List<Recipient> getGroups(@NonNull String query) {
if (TextUtils.isEmpty(query)) {
return Collections.emptyList();
}
List<Recipient> recipients = new ArrayList<>();
try (GroupTable.Reader reader = groupDatabase.queryGroupsByTitle(query, false, true, true)) {
GroupRecord groupRecord;
while ((groupRecord = reader.getNext()) != null) {
RecipientId recipientId = recipientTable.getOrInsertFromGroupId(groupRecord.getId());
recipients.add(Recipient.resolved(recipientId));
}
}
return recipients;
}
interface Callback<E> {
void onComplete(E result);
}
}