mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 07:58:34 +00:00
Fix contact selection behavior when searching and clear search on selection.
This commit is contained in:
parent
ae87d23003
commit
7f2439f1e9
@ -44,6 +44,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.loader.app.LoaderManager;
|
import androidx.loader.app.LoaderManager;
|
||||||
import androidx.loader.content.Loader;
|
import androidx.loader.content.Loader;
|
||||||
|
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
@ -195,6 +196,12 @@ public final class ContactSelectionListFragment extends Fragment
|
|||||||
constraintLayout = view.findViewById(R.id.container);
|
constraintLayout = view.findViewById(R.id.container);
|
||||||
|
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
|
recyclerView.setItemAnimator(new DefaultItemAnimator() {
|
||||||
|
@Override
|
||||||
|
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
swipeRefresh.setEnabled(requireActivity().getIntent().getBooleanExtra(REFRESHABLE, true));
|
swipeRefresh.setEnabled(requireActivity().getIntent().getBooleanExtra(REFRESHABLE, true));
|
||||||
|
|
||||||
@ -335,6 +342,10 @@ public final class ContactSelectionListFragment extends Fragment
|
|||||||
swipeRefresh.setRefreshing(false);
|
swipeRefresh.setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasQueryFilter() {
|
||||||
|
return !TextUtils.isEmpty(cursorFilter);
|
||||||
|
}
|
||||||
|
|
||||||
public void setRefreshing(boolean refreshing) {
|
public void setRefreshing(boolean refreshing) {
|
||||||
swipeRefresh.setRefreshing(refreshing);
|
swipeRefresh.setRefreshing(refreshing);
|
||||||
}
|
}
|
||||||
@ -455,7 +466,8 @@ public final class ContactSelectionListFragment extends Fragment
|
|||||||
if (uuid.isPresent()) {
|
if (uuid.isPresent()) {
|
||||||
Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber());
|
Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber());
|
||||||
SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber());
|
SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber());
|
||||||
markContactSelected(selected, contact);
|
markContactSelected(selected);
|
||||||
|
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
|
||||||
|
|
||||||
if (onContactSelectedListener != null) {
|
if (onContactSelectedListener != null) {
|
||||||
onContactSelectedListener.onContactSelected(Optional.of(recipient.getId()), null);
|
onContactSelectedListener.onContactSelected(Optional.of(recipient.getId()), null);
|
||||||
@ -469,14 +481,16 @@ public final class ContactSelectionListFragment extends Fragment
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
markContactSelected(selectedContact, contact);
|
markContactSelected(selectedContact);
|
||||||
|
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
|
||||||
|
|
||||||
if (onContactSelectedListener != null) {
|
if (onContactSelectedListener != null) {
|
||||||
onContactSelectedListener.onContactSelected(contact.getRecipientId(), contact.getNumber());
|
onContactSelectedListener.onContactSelected(contact.getRecipientId(), contact.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
markContactUnselected(selectedContact, contact);
|
markContactUnselected(selectedContact);
|
||||||
|
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
|
||||||
|
|
||||||
if (onContactSelectedListener != null) {
|
if (onContactSelectedListener != null) {
|
||||||
onContactSelectedListener.onContactDeselected(contact.getRecipientId(), contact.getNumber());
|
onContactSelectedListener.onContactDeselected(contact.getRecipientId(), contact.getNumber());
|
||||||
@ -488,17 +502,16 @@ public final class ContactSelectionListFragment extends Fragment
|
|||||||
return getChipCount() >= selectionLimit;
|
return getChipCount() >= selectionLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markContactSelected(@NonNull SelectedContact selectedContact, @NonNull ContactSelectionListItem listItem) {
|
private void markContactSelected(@NonNull SelectedContact selectedContact) {
|
||||||
cursorRecyclerViewAdapter.addSelectedContact(selectedContact);
|
cursorRecyclerViewAdapter.addSelectedContact(selectedContact);
|
||||||
listItem.setChecked(true);
|
|
||||||
if (isMulti() && FeatureFlags.newGroupUI()) {
|
if (isMulti() && FeatureFlags.newGroupUI()) {
|
||||||
addChipForContact(listItem, selectedContact);
|
addChipForSelectedContact(selectedContact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markContactUnselected(@NonNull SelectedContact selectedContact, @NonNull ContactSelectionListItem listItem) {
|
private void markContactUnselected(@NonNull SelectedContact selectedContact) {
|
||||||
cursorRecyclerViewAdapter.removeFromSelectedContacts(selectedContact);
|
cursorRecyclerViewAdapter.removeFromSelectedContacts(selectedContact);
|
||||||
listItem.setChecked(false);
|
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
|
||||||
removeChipForContact(selectedContact);
|
removeChipForContact(selectedContact);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,17 +530,23 @@ public final class ContactSelectionListFragment extends Fragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addChipForContact(@NonNull ContactSelectionListItem contact, @NonNull SelectedContact selectedContact) {
|
private void addChipForSelectedContact(@NonNull SelectedContact selectedContact) {
|
||||||
|
SimpleTask.run(getViewLifecycleOwner().getLifecycle(),
|
||||||
|
() -> Recipient.resolved(selectedContact.getOrCreateRecipientId(requireContext())),
|
||||||
|
resolved -> addChipForRecipient(resolved, selectedContact));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addChipForRecipient(@NonNull Recipient recipient, @NonNull SelectedContact selectedContact) {
|
||||||
final ContactChip chip = new ContactChip(requireContext());
|
final ContactChip chip = new ContactChip(requireContext());
|
||||||
|
|
||||||
if (getChipCount() == 0) {
|
if (getChipCount() == 0) {
|
||||||
setChipGroupVisibility(ConstraintSet.VISIBLE);
|
setChipGroupVisibility(ConstraintSet.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
chip.setText(contact.getChipName());
|
chip.setText(recipient.getShortDisplayName(requireContext()));
|
||||||
chip.setContact(selectedContact);
|
chip.setContact(selectedContact);
|
||||||
chip.setCloseIconVisible(true);
|
chip.setCloseIconVisible(true);
|
||||||
chip.setOnCloseIconClickListener(view -> markContactUnselected(selectedContact, contact));
|
chip.setOnCloseIconClickListener(view -> markContactUnselected(selectedContact));
|
||||||
|
|
||||||
chipGroup.getLayoutTransition().addTransitionListener(new LayoutTransition.TransitionListener() {
|
chipGroup.getLayoutTransition().addTransitionListener(new LayoutTransition.TransitionListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -538,18 +557,13 @@ public final class ContactSelectionListFragment extends Fragment
|
|||||||
public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
|
public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
|
||||||
if (view == chip && transitionType == LayoutTransition.APPEARING) {
|
if (view == chip && transitionType == LayoutTransition.APPEARING) {
|
||||||
chipGroup.getLayoutTransition().removeTransitionListener(this);
|
chipGroup.getLayoutTransition().removeTransitionListener(this);
|
||||||
registerChipRecipientObserver(chip, contact.getRecipient());
|
registerChipRecipientObserver(chip, recipient.live());
|
||||||
chipGroup.post(ContactSelectionListFragment.this::smoothScrollChipsToEnd);
|
chipGroup.post(ContactSelectionListFragment.this::smoothScrollChipsToEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
LiveRecipient recipient = contact.getRecipient();
|
chip.setAvatar(glideRequests, recipient, () -> addChip(chip));
|
||||||
if (recipient != null) {
|
|
||||||
chip.setAvatar(glideRequests, recipient.get(), () -> addChip(chip));
|
|
||||||
} else {
|
|
||||||
addChip(chip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addChip(@NonNull ContactChip chip) {
|
private void addChip(@NonNull ContactChip chip) {
|
||||||
|
@ -64,6 +64,8 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
|||||||
private final static int STYLE_ATTRIBUTES[] = new int[]{R.attr.contact_selection_push_user,
|
private final static int STYLE_ATTRIBUTES[] = new int[]{R.attr.contact_selection_push_user,
|
||||||
R.attr.contact_selection_lay_user};
|
R.attr.contact_selection_lay_user};
|
||||||
|
|
||||||
|
public static final int PAYLOAD_SELECTION_CHANGE = 1;
|
||||||
|
|
||||||
private final boolean multiSelect;
|
private final boolean multiSelect;
|
||||||
private final LayoutInflater li;
|
private final LayoutInflater li;
|
||||||
private final TypedArray drawables;
|
private final TypedArray drawables;
|
||||||
@ -175,6 +177,7 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
|||||||
@Override
|
@Override
|
||||||
public long getHeaderId(int i) {
|
public long getHeaderId(int i) {
|
||||||
if (!isActiveCursor()) return -1;
|
if (!isActiveCursor()) return -1;
|
||||||
|
else if (i == -1) return -1;
|
||||||
|
|
||||||
int contactType = getContactType(i);
|
int contactType = getContactType(i);
|
||||||
|
|
||||||
@ -216,6 +219,24 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor, @NonNull List<Object> payloads) {
|
||||||
|
if (!arePayloadsValid(payloads)) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
String rawId = cursor.getString(cursor.getColumnIndexOrThrow(ContactRepository.ID_COLUMN));
|
||||||
|
RecipientId id = rawId != null ? RecipientId.from(rawId) : null;
|
||||||
|
int numberType = cursor.getInt(cursor.getColumnIndexOrThrow(ContactRepository.NUMBER_TYPE_COLUMN));
|
||||||
|
String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactRepository.NUMBER_COLUMN));
|
||||||
|
|
||||||
|
if (numberType == ContactRepository.NEW_USERNAME_TYPE) {
|
||||||
|
viewHolder.setChecked(selectedContacts.contains(SelectedContact.forUsername(id, number)));
|
||||||
|
} else {
|
||||||
|
viewHolder.setChecked(selectedContacts.contains(SelectedContact.forPhone(id, number)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(@NonNull Cursor cursor) {
|
public int getItemViewType(@NonNull Cursor cursor) {
|
||||||
if (cursor.getInt(cursor.getColumnIndexOrThrow(ContactRepository.CONTACT_TYPE_COLUMN)) == ContactRepository.DIVIDER_TYPE) {
|
if (cursor.getInt(cursor.getColumnIndexOrThrow(ContactRepository.CONTACT_TYPE_COLUMN)) == ContactRepository.DIVIDER_TYPE) {
|
||||||
@ -225,7 +246,6 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position) {
|
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position) {
|
||||||
return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.contact_selection_recyclerview_header, parent, false));
|
return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.contact_selection_recyclerview_header, parent, false));
|
||||||
@ -236,6 +256,11 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
|||||||
((TextView)viewHolder.itemView).setText(getSpannedHeaderString(position));
|
((TextView)viewHolder.itemView).setText(getSpannedHeaderString(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean arePayloadsValid(@NonNull List<Object> payloads) {
|
||||||
|
return payloads.size() == 1 && payloads.get(0).equals(PAYLOAD_SELECTION_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemViewRecycled(ViewHolder holder) {
|
public void onItemViewRecycled(ViewHolder holder) {
|
||||||
holder.unbind(glideRequests);
|
holder.unbind(glideRequests);
|
||||||
|
@ -31,6 +31,8 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RecyclerView.Adapter that manages a Cursor, comparable to the CursorAdapter usable in ListView/GridView.
|
* RecyclerView.Adapter that manages a Cursor, comparable to the CursorAdapter usable in ListView/GridView.
|
||||||
*/
|
*/
|
||||||
@ -173,6 +175,16 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
|
|||||||
|
|
||||||
public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType);
|
public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onBindViewHolder(@NonNull ViewHolder viewHolder, int position, @NonNull List<Object> payloads) {
|
||||||
|
if (arePayloadsValid(payloads) && !isHeaderPosition(position) && !isFooterPosition(position)) {
|
||||||
|
if (isFastAccessPosition(position)) onBindFastAccessItemViewHolder((VH)viewHolder, position, payloads);
|
||||||
|
else onBindItemViewHolder((VH)viewHolder, getCursorAtPositionOrThrow(position), payloads);
|
||||||
|
} else {
|
||||||
|
onBindViewHolder(viewHolder, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public final void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
public final void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
@ -188,8 +200,17 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
|
|||||||
|
|
||||||
public abstract void onBindItemViewHolder(VH viewHolder, @NonNull Cursor cursor);
|
public abstract void onBindItemViewHolder(VH viewHolder, @NonNull Cursor cursor);
|
||||||
|
|
||||||
protected void onBindFastAccessItemViewHolder(VH viewHolder, int position) {
|
protected boolean arePayloadsValid(@NonNull List<Object> payloads) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onBindItemViewHolder(VH viewHolder, @NonNull Cursor cursor, @NonNull List<Object> payloads) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onBindFastAccessItemViewHolder(VH viewHolder, int position) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onBindFastAccessItemViewHolder(VH viewHolder, int position, @NonNull List<Object> payloads) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,6 +82,10 @@ public class CreateGroupActivity extends ContactSelectionActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContactSelected(Optional<RecipientId> recipientId, String number) {
|
public void onContactSelected(Optional<RecipientId> recipientId, String number) {
|
||||||
|
if (contactsFragment.hasQueryFilter()) {
|
||||||
|
getToolbar().clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (contactsFragment.getSelectedContactsCount() >= MINIMUM_GROUP_SIZE) {
|
if (contactsFragment.getSelectedContactsCount() >= MINIMUM_GROUP_SIZE) {
|
||||||
enableNext();
|
enableNext();
|
||||||
}
|
}
|
||||||
@ -89,6 +93,10 @@ public class CreateGroupActivity extends ContactSelectionActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {
|
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {
|
||||||
|
if (contactsFragment.hasQueryFilter()) {
|
||||||
|
getToolbar().clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (contactsFragment.getSelectedContactsCount() < MINIMUM_GROUP_SIZE) {
|
if (contactsFragment.getSelectedContactsCount() < MINIMUM_GROUP_SIZE) {
|
||||||
disableNext();
|
disableNext();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user