diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactAdapter.java deleted file mode 100644 index 0c58f76a2f..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactAdapter.java +++ /dev/null @@ -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 { - - 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 selected; - private final CameraContactListener cameraContactListener; - - - private final List sections = new ArrayList(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 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 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 { - - private final String tag; - private final int titleResId; - private final List recipients; - - public ContactSection(@NonNull String tag, @StringRes int titleResId, @NonNull List 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 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 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(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionAdapter.java deleted file mode 100644 index 96e7214f7e..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionAdapter.java +++ /dev/null @@ -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 { - - private final List recipients = new ArrayList<>(); - private final StableIdGenerator 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 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 : ","); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionFragment.java deleted file mode 100644 index 64cf2da688..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionFragment.java +++ /dev/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 recipients); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionViewModel.java deleted file mode 100644 index ff4a6ca286..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactSelectionViewModel.java +++ /dev/null @@ -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 contacts; - private final SingleLiveEvent error; - private final Set 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 getContacts() { - return contacts; - } - - LiveData 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 selected; - private final String query; - - ContactState(@NonNull CameraContacts contacts, @NonNull List selected, @Nullable String query) { - this.contacts = contacts; - this.selected = selected; - this.query = query; - } - - public CameraContacts getContacts() { - return contacts; - } - - public List 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 create(@NonNull Class modelClass) { - //noinspection ConstantConditions - return modelClass.cast(new CameraContactSelectionViewModel(repository)); - } - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContacts.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContacts.java deleted file mode 100644 index 3e6c526a68..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContacts.java +++ /dev/null @@ -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 recents; - private final List contacts; - private final List groups; - - public CameraContacts(@NonNull List recents, @NonNull List contacts, @NonNull List groups) { - this.recents = recents; - this.contacts = contacts; - this.groups = groups; - } - - public @NonNull List getRecents() { - return recents; - } - - public @NonNull List getContacts() { - return contacts; - } - - public @NonNull List getGroups() { - return groups; - } - - public boolean isEmpty() { - return recents.isEmpty() && contacts.isEmpty() && groups.isEmpty(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactsRepository.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactsRepository.java deleted file mode 100644 index b26a1b2161..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraContactsRepository.java +++ /dev/null @@ -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 callback) { - getCameraContacts("", callback); - } - - void getCameraContacts(@NonNull String query, @NonNull Callback callback) { - serialExecutor.execute(() -> { - Future> recents = parallelExecutor.submit(() -> getRecents(query)); - Future> contacts = parallelExecutor.submit(() -> getContacts(query)); - Future> 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 getRecents(@NonNull String query) { - if (!TextUtils.isEmpty(query)) { - return Collections.emptyList(); - } - - List 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 getContacts(@NonNull String query) { - List 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 getGroups(@NonNull String query) { - if (TextUtils.isEmpty(query)) { - return Collections.emptyList(); - } - - List 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 { - void onComplete(E result); - } -} diff --git a/app/src/main/res/drawable-hdpi/no_contacts.png b/app/src/main/res/drawable-hdpi/no_contacts.png deleted file mode 100644 index 941759dd02..0000000000 Binary files a/app/src/main/res/drawable-hdpi/no_contacts.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/no_contacts.png b/app/src/main/res/drawable-mdpi/no_contacts.png deleted file mode 100644 index 8a98e8de59..0000000000 Binary files a/app/src/main/res/drawable-mdpi/no_contacts.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/no_contacts.png b/app/src/main/res/drawable-xhdpi/no_contacts.png deleted file mode 100644 index 083b80d1c8..0000000000 Binary files a/app/src/main/res/drawable-xhdpi/no_contacts.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/no_contacts.png b/app/src/main/res/drawable-xxhdpi/no_contacts.png deleted file mode 100644 index 5bf45a4bf9..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/no_contacts.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/no_contacts.webp b/app/src/main/res/drawable-xxxhdpi/no_contacts.webp deleted file mode 100644 index df93c934e6..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/no_contacts.webp and /dev/null differ diff --git a/app/src/main/res/layout/camera_contact_contact_item.xml b/app/src/main/res/layout/camera_contact_contact_item.xml deleted file mode 100644 index e0d912b3e1..0000000000 --- a/app/src/main/res/layout/camera_contact_contact_item.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/camera_contact_header_item.xml b/app/src/main/res/layout/camera_contact_header_item.xml deleted file mode 100644 index ac267691be..0000000000 --- a/app/src/main/res/layout/camera_contact_header_item.xml +++ /dev/null @@ -1,15 +0,0 @@ - - diff --git a/app/src/main/res/layout/camera_contact_invite_item.xml b/app/src/main/res/layout/camera_contact_invite_item.xml deleted file mode 100644 index e02459f0c0..0000000000 --- a/app/src/main/res/layout/camera_contact_invite_item.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/camera_contact_selection_fragment.xml b/app/src/main/res/layout/camera_contact_selection_fragment.xml deleted file mode 100644 index 9ca3ee9418..0000000000 --- a/app/src/main/res/layout/camera_contact_selection_fragment.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/camera_contact_selection_item.xml b/app/src/main/res/layout/camera_contact_selection_item.xml deleted file mode 100644 index 13f1f48075..0000000000 --- a/app/src/main/res/layout/camera_contact_selection_item.xml +++ /dev/null @@ -1,9 +0,0 @@ - - diff --git a/app/src/main/res/menu/camera_contacts.xml b/app/src/main/res/menu/camera_contacts.xml deleted file mode 100644 index bea0dd79fa..0000000000 --- a/app/src/main/res/menu/camera_contacts.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 2b6a4b50e7..960c3ddca0 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -30,7 +30,6 @@ 104dp 69dp - 16dp 124dp 76dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4894966794..74b8177d4a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -331,20 +331,6 @@ Send - - Recent contacts - Signal contacts - Signal groups - - - You can share with a maximum of %d chat. - You can share with a maximum of %d chats. - - Select Signal recipients - No Signal contacts - You can only use the camera button to send photos to Signal contacts. - Can\'t find who you\'re looking for? - Invite a contact to join Signal Search