mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-27 12:15:50 +01:00
Group contact chips behind feature flag.
This commit is contained in:
committed by
Greyson Parrelli
parent
8e0fba7992
commit
0b279d1df3
@@ -0,0 +1,117 @@
|
||||
package org.thoughtcrime.securesms.contacts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.google.android.material.chip.Chip;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public final class ContactChip extends Chip {
|
||||
|
||||
@Nullable private SelectedContact contact;
|
||||
|
||||
public ContactChip(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ContactChip(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ContactChip(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public void setContact(@NonNull SelectedContact contact) {
|
||||
this.contact = contact;
|
||||
}
|
||||
|
||||
public @Nullable SelectedContact getContact() {
|
||||
return contact;
|
||||
}
|
||||
|
||||
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient) {
|
||||
if (recipient != null) {
|
||||
requestManager.clear(this);
|
||||
|
||||
Drawable fallbackContactPhotoDrawable = recipient.getFallbackContactPhotoDrawable(getContext(), false);
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto();
|
||||
|
||||
if (contactPhoto == null) {
|
||||
setChipIcon(new HalfScaleDrawable(fallbackContactPhotoDrawable));
|
||||
} else {
|
||||
requestManager.load(contactPhoto)
|
||||
.fallback(fallbackContactPhotoDrawable)
|
||||
.error(fallbackContactPhotoDrawable)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.circleCrop()
|
||||
.into(new CustomTarget<Drawable>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
|
||||
setChipIcon(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCleared(@Nullable Drawable placeholder) {
|
||||
setChipIcon(placeholder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class HalfScaleDrawable extends Drawable {
|
||||
|
||||
private final Drawable fallbackContactPhotoDrawable;
|
||||
|
||||
HalfScaleDrawable(Drawable fallbackContactPhotoDrawable) {
|
||||
this.fallbackContactPhotoDrawable = fallbackContactPhotoDrawable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBounds(int left, int top, int right, int bottom) {
|
||||
super.setBounds(left, top, right, bottom);
|
||||
fallbackContactPhotoDrawable.setBounds(left, top, 2 * right - left, 2 * bottom - top);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBounds(@NonNull Rect bounds) {
|
||||
super.setBounds(bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
canvas.save();
|
||||
canvas.scale(0.5f, 0.5f);
|
||||
fallbackContactPhotoDrawable.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(@Nullable ColorFilter colorFilter) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.OPAQUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration.StickyHeaderAdapter;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* List adapter to display all contacts and their related information
|
||||
@@ -70,7 +70,26 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
||||
private final ItemClickListener clickListener;
|
||||
private final GlideRequests glideRequests;
|
||||
|
||||
private final Set<SelectedContact> selectedContacts = new HashSet<>();
|
||||
private final SelectedContactSet selectedContacts = new SelectedContactSet();
|
||||
|
||||
public void clearSelectedContacts() {
|
||||
selectedContacts.clear();
|
||||
}
|
||||
|
||||
public boolean isSelectedContact(@NonNull SelectedContact contact) {
|
||||
return selectedContacts.contains(contact);
|
||||
}
|
||||
|
||||
public void addSelectedContact(@NonNull SelectedContact contact) {
|
||||
if (!selectedContacts.add(contact)) {
|
||||
Log.i(TAG, "Contact was already selected, possibly by another identifier");
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromSelectedContacts(@NonNull SelectedContact selectedContact) {
|
||||
int removed = selectedContacts.remove(selectedContact);
|
||||
Log.i(TAG, String.format(Locale.US, "Removed %d selected contacts that matched", removed));
|
||||
}
|
||||
|
||||
public abstract static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@@ -227,8 +246,8 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
||||
return getHeaderString(position);
|
||||
}
|
||||
|
||||
public Set<SelectedContact> getSelectedContacts() {
|
||||
return selectedContacts;
|
||||
public List<SelectedContact> getSelectedContacts() {
|
||||
return selectedContacts.getContacts();
|
||||
}
|
||||
|
||||
private CharSequence getSpannedHeaderString(int position) {
|
||||
|
||||
@@ -35,6 +35,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientF
|
||||
private CheckBox checkBox;
|
||||
|
||||
private String number;
|
||||
private String chipName;
|
||||
private int contactType;
|
||||
private LiveRecipient recipient;
|
||||
private GlideRequests glideRequests;
|
||||
@@ -128,8 +129,10 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientF
|
||||
|
||||
if (recipient != null) {
|
||||
this.nameView.setText(recipient);
|
||||
chipName = recipient.getShortDisplayName(getContext());
|
||||
} else {
|
||||
this.nameView.setText(name);
|
||||
chipName = name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +140,14 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientF
|
||||
return number;
|
||||
}
|
||||
|
||||
public String getChipName() {
|
||||
return chipName;
|
||||
}
|
||||
|
||||
public @Nullable LiveRecipient getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public boolean isUsernameType() {
|
||||
return contactType == ContactRepository.NEW_USERNAME_TYPE;
|
||||
}
|
||||
|
||||
@@ -8,16 +8,12 @@ import androidx.annotation.Nullable;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Model for a contact and the various ways it could be represented. Used in situations where we
|
||||
* don't want to create Recipients for the wrapped data (like a custom-entered phone number for
|
||||
* someone you don't yet have a conversation with).
|
||||
*
|
||||
* Designed so that two instances will be equal if *any* of its properties match.
|
||||
*/
|
||||
public class SelectedContact {
|
||||
public final class SelectedContact {
|
||||
private final RecipientId recipientId;
|
||||
private final String number;
|
||||
private final String username;
|
||||
@@ -46,19 +42,14 @@ public class SelectedContact {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SelectedContact that = (SelectedContact) o;
|
||||
/**
|
||||
* Returns true iff any non-null property matches one on the other contact.
|
||||
*/
|
||||
public boolean matches(@Nullable SelectedContact other) {
|
||||
if (other == null) return false;
|
||||
|
||||
return Objects.equals(recipientId, that.recipientId) ||
|
||||
Objects.equals(number, that.number) ||
|
||||
Objects.equals(username, that.username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(recipientId, number, username);
|
||||
return recipientId != null && recipientId.equals(other.recipientId) ||
|
||||
number != null && number .equals(other.number) ||
|
||||
username != null && username .equals(other.username);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.thoughtcrime.securesms.contacts;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Specialised set for {@link SelectedContact} that will not allow more than one entry that
|
||||
* {@link SelectedContact#matches(SelectedContact)} any other.
|
||||
*/
|
||||
public final class SelectedContactSet {
|
||||
|
||||
private final List<SelectedContact> contacts = new LinkedList<>();
|
||||
|
||||
public boolean add(@NonNull SelectedContact contact) {
|
||||
if (contains(contact)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
contacts.add(contact);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean contains(@NonNull SelectedContact otherContact) {
|
||||
for (SelectedContact contact : contacts) {
|
||||
if (otherContact.matches(contact)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<SelectedContact> getContacts() {
|
||||
return new ArrayList<>(contacts);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
contacts.clear();
|
||||
}
|
||||
|
||||
public int remove(@NonNull SelectedContact otherContact) {
|
||||
int removeCount = 0;
|
||||
Iterator<SelectedContact> iterator = contacts.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
SelectedContact next = iterator.next();
|
||||
if (next.matches(otherContact)) {
|
||||
iterator.remove();
|
||||
removeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return removeCount;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user