mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-25 13:58:40 +00:00
Refactor ContactSelectionListAdapter and associated views.
Fixes #3181 Closes #3197 // FREEBIE
This commit is contained in:
@@ -21,27 +21,15 @@ import android.content.res.TypedArray;
|
||||
import android.database.Cursor;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.BitmapWorkerRunnable;
|
||||
import org.thoughtcrime.securesms.util.BitmapWorkerRunnable.AsyncDrawable;
|
||||
import org.thoughtcrime.securesms.util.TaggedFutureTask;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
|
||||
|
||||
@@ -53,53 +41,22 @@ import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
|
||||
public class ContactSelectionListAdapter extends CursorAdapter
|
||||
implements StickyListHeadersAdapter
|
||||
{
|
||||
private final static String TAG = "ContactListAdapter";
|
||||
|
||||
private final static ExecutorService photoResolver = Util.newSingleThreadedLifoExecutor();
|
||||
private final static String TAG = ContactSelectionListAdapter.class.getSimpleName();
|
||||
|
||||
private final static int STYLE_ATTRIBUTES[] = new int[]{R.attr.contact_selection_push_user,
|
||||
R.attr.contact_selection_lay_user,
|
||||
R.attr.contact_selection_label_text};
|
||||
R.attr.contact_selection_lay_user};
|
||||
|
||||
private int TYPE_COLUMN = -1;
|
||||
private int NAME_COLUMN = -1;
|
||||
private int NUMBER_COLUMN = -1;
|
||||
private int NUMBER_TYPE_COLUMN = -1;
|
||||
private int LABEL_COLUMN = -1;
|
||||
private int ID_COLUMN = -1;
|
||||
|
||||
private final Context context;
|
||||
private final boolean multiSelect;
|
||||
private final LayoutInflater li;
|
||||
private final TypedArray drawables;
|
||||
private final int scaledPhotoSize;
|
||||
|
||||
private final HashMap<Long, ContactAccessor.ContactData> selectedContacts = new HashMap<>();
|
||||
private final HashMap<Long, String> selectedContacts = new HashMap<>();
|
||||
|
||||
public ContactSelectionListAdapter(Context context, Cursor cursor, boolean multiSelect) {
|
||||
super(context, cursor, 0);
|
||||
this.context = context;
|
||||
this.li = LayoutInflater.from(context);
|
||||
this.drawables = context.obtainStyledAttributes(STYLE_ATTRIBUTES);
|
||||
this.multiSelect = multiSelect;
|
||||
this.scaledPhotoSize = context.getResources().getDimensionPixelSize(R.dimen.contact_selection_photo_size);
|
||||
}
|
||||
|
||||
public static class ViewHolder {
|
||||
public CheckBox checkBox;
|
||||
public TextView name;
|
||||
public TextView number;
|
||||
public ImageView contactPhoto;
|
||||
public int position;
|
||||
}
|
||||
|
||||
public static class DataHolder {
|
||||
public int type;
|
||||
public String name;
|
||||
public String number;
|
||||
public int numberType;
|
||||
public String label;
|
||||
public long id;
|
||||
this.li = LayoutInflater.from(context);
|
||||
this.drawables = context.obtainStyledAttributes(STYLE_ATTRIBUTES);
|
||||
this.multiSelect = multiSelect;
|
||||
}
|
||||
|
||||
public static class HeaderViewHolder {
|
||||
@@ -108,148 +65,63 @@ public class ContactSelectionListAdapter extends CursorAdapter
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
final View v = li.inflate(R.layout.push_contact_selection_list_item, parent, false);
|
||||
final ViewHolder holder = new ViewHolder();
|
||||
|
||||
if (v != null) {
|
||||
holder.name = (TextView) v.findViewById(R.id.name);
|
||||
holder.number = (TextView) v.findViewById(R.id.number);
|
||||
holder.checkBox = (CheckBox) v.findViewById(R.id.check_box);
|
||||
holder.contactPhoto = (ImageView) v.findViewById(R.id.contact_photo_image);
|
||||
|
||||
if (!multiSelect) holder.checkBox.setVisibility(View.GONE);
|
||||
|
||||
v.setTag(R.id.holder_tag, holder);
|
||||
v.setTag(R.id.contact_info_tag, new DataHolder());
|
||||
}
|
||||
return v;
|
||||
return li.inflate(R.layout.push_contact_selection_list_item, parent, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
final DataHolder contactData = (DataHolder) view.getTag(R.id.contact_info_tag);
|
||||
final ViewHolder holder = (ViewHolder) view.getTag(R.id.holder_tag);
|
||||
if (holder == null) {
|
||||
Log.w(TAG, "ViewHolder was null. This should not happen.");
|
||||
return;
|
||||
}
|
||||
if (contactData == null) {
|
||||
Log.w(TAG, "DataHolder was null. This should not happen.");
|
||||
return;
|
||||
}
|
||||
if (ID_COLUMN < 0) {
|
||||
populateColumnIndices(cursor);
|
||||
}
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ContactsDatabase.ID_COLUMN));
|
||||
int type = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.TYPE_COLUMN));
|
||||
String name = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NAME_COLUMN));
|
||||
String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
|
||||
int numberType = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_TYPE_COLUMN));
|
||||
String label = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.LABEL_COLUMN));
|
||||
String labelText = ContactsContract.CommonDataKinds.Phone.getTypeLabel(context.getResources(),
|
||||
numberType, label).toString();
|
||||
|
||||
contactData.type = cursor.getInt(TYPE_COLUMN);
|
||||
contactData.name = cursor.getString(NAME_COLUMN);
|
||||
contactData.number = cursor.getString(NUMBER_COLUMN);
|
||||
contactData.numberType = cursor.getInt(NUMBER_TYPE_COLUMN);
|
||||
contactData.label = cursor.getString(LABEL_COLUMN);
|
||||
contactData.id = cursor.getLong(ID_COLUMN);
|
||||
int color = (type == ContactsDatabase.PUSH_TYPE) ? drawables.getColor(0, 0xa0000000) :
|
||||
drawables.getColor(1, 0xff000000);
|
||||
|
||||
if (contactData.type != ContactsDatabase.PUSH_TYPE) {
|
||||
holder.name.setTextColor(drawables.getColor(1, 0xff000000));
|
||||
holder.number.setTextColor(drawables.getColor(1, 0xff000000));
|
||||
} else {
|
||||
holder.name.setTextColor(drawables.getColor(0, 0xa0000000));
|
||||
holder.number.setTextColor(drawables.getColor(0, 0xa0000000));
|
||||
}
|
||||
|
||||
if (selectedContacts.containsKey(contactData.id)) {
|
||||
holder.checkBox.setChecked(true);
|
||||
} else {
|
||||
holder.checkBox.setChecked(false);
|
||||
}
|
||||
|
||||
holder.name.setText(contactData.name);
|
||||
|
||||
if (contactData.number == null || contactData.number.isEmpty()) {
|
||||
holder.name.setEnabled(false);
|
||||
holder.number.setText("");
|
||||
} else if (contactData.type == ContactsDatabase.PUSH_TYPE) {
|
||||
holder.number.setText(contactData.number);
|
||||
} else {
|
||||
final CharSequence label = ContactsContract.CommonDataKinds.Phone.getTypeLabel(context.getResources(),
|
||||
contactData.numberType, contactData.label);
|
||||
final CharSequence numberWithLabel = contactData.number + " " + label;
|
||||
final Spannable numberLabelSpan = new SpannableString(numberWithLabel);
|
||||
numberLabelSpan.setSpan(new ForegroundColorSpan(drawables.getColor(2, 0xff444444)), contactData.number.length(), numberWithLabel.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
holder.number.setText(numberLabelSpan);
|
||||
}
|
||||
holder.contactPhoto.setImageDrawable(ContactPhotoFactory.getLoadingPhoto(context));
|
||||
if (contactData.id > -1) loadBitmap(contactData.number, holder.contactPhoto);
|
||||
((ContactSelectionListItem)view).unbind();
|
||||
((ContactSelectionListItem)view).set(id, type, name, number, labelText, color, multiSelect);
|
||||
((ContactSelectionListItem)view).setChecked(selectedContacts.containsKey(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getHeaderView(int i, View convertView, ViewGroup viewGroup) {
|
||||
final Cursor c = getCursor();
|
||||
final HeaderViewHolder holder;
|
||||
Cursor cursor = getCursor();
|
||||
|
||||
HeaderViewHolder holder;
|
||||
|
||||
if (convertView == null) {
|
||||
holder = new HeaderViewHolder();
|
||||
holder = new HeaderViewHolder();
|
||||
convertView = li.inflate(R.layout.push_contact_selection_list_header, viewGroup, false);
|
||||
holder.text = (TextView) convertView.findViewById(R.id.text);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (HeaderViewHolder) convertView.getTag();
|
||||
}
|
||||
c.moveToPosition(i);
|
||||
|
||||
final int type = c.getInt(c.getColumnIndexOrThrow(ContactsDatabase.TYPE_COLUMN));
|
||||
final int headerTextRes;
|
||||
switch (type) {
|
||||
case 1: headerTextRes = R.string.contact_selection_list__header_textsecure_users; break;
|
||||
default: headerTextRes = R.string.contact_selection_list__header_other; break;
|
||||
}
|
||||
holder.text.setText(headerTextRes);
|
||||
cursor.moveToPosition(i);
|
||||
|
||||
int type = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.TYPE_COLUMN));
|
||||
|
||||
if (type == ContactsDatabase.PUSH_TYPE) holder.text.setText(R.string.contact_selection_list__header_textsecure_users);
|
||||
else holder.text.setText(R.string.contact_selection_list__header_other);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getHeaderId(int i) {
|
||||
final Cursor c = getCursor();
|
||||
c.moveToPosition(i);
|
||||
return c.getInt(c.getColumnIndexOrThrow(ContactsDatabase.TYPE_COLUMN));
|
||||
Cursor cursor = getCursor();
|
||||
cursor.moveToPosition(i);
|
||||
|
||||
return cursor.getInt(cursor.getColumnIndexOrThrow(ContactsDatabase.TYPE_COLUMN));
|
||||
}
|
||||
|
||||
public boolean cancelPotentialWork(String number, ImageView imageView) {
|
||||
final TaggedFutureTask<?> bitmapWorkerTask = AsyncDrawable.getBitmapWorkerTask(imageView);
|
||||
|
||||
if (bitmapWorkerTask != null) {
|
||||
final Object tag = bitmapWorkerTask.getTag();
|
||||
if (tag != null && !tag.equals(number)) {
|
||||
bitmapWorkerTask.cancel(true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME -- It should be unnecessary to duplicate the existing asynchronous resolution
|
||||
// infrastructure we've built for Recipient objects here.
|
||||
|
||||
public void loadBitmap(String number, ImageView imageView) {
|
||||
if (cancelPotentialWork(number, imageView)) {
|
||||
final BitmapWorkerRunnable runnable = new BitmapWorkerRunnable(context, imageView, number, scaledPhotoSize);
|
||||
final TaggedFutureTask<?> task = new TaggedFutureTask<Void>(runnable, null, number);
|
||||
final AsyncDrawable asyncDrawable = new AsyncDrawable(task);
|
||||
|
||||
imageView.setImageDrawable(asyncDrawable);
|
||||
if (!task.isCancelled()) photoResolver.execute(new FutureTask<Void>(task, null));
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Long,ContactAccessor.ContactData> getSelectedContacts() {
|
||||
public Map<Long, String> getSelectedContacts() {
|
||||
return selectedContacts;
|
||||
}
|
||||
|
||||
private void populateColumnIndices(final Cursor cursor) {
|
||||
this.TYPE_COLUMN = cursor.getColumnIndexOrThrow(ContactsDatabase.TYPE_COLUMN);
|
||||
this.NAME_COLUMN = cursor.getColumnIndexOrThrow(ContactsDatabase.NAME_COLUMN);
|
||||
this.NUMBER_COLUMN = cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN);
|
||||
this.NUMBER_TYPE_COLUMN = cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_TYPE_COLUMN);
|
||||
this.LABEL_COLUMN = cursor.getColumnIndexOrThrow(ContactsDatabase.LABEL_COLUMN);
|
||||
this.ID_COLUMN = cursor.getColumnIndexOrThrow(ContactsDatabase.ID_COLUMN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package org.thoughtcrime.securesms.contacts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
|
||||
public class ContactSelectionListItem extends RelativeLayout implements Recipient.RecipientModifiedListener {
|
||||
|
||||
private ImageView contactPhotoImage;
|
||||
private TextView numberView;
|
||||
private TextView nameView;
|
||||
private TextView labelView;
|
||||
private CheckBox checkBox;
|
||||
|
||||
private long id;
|
||||
private String number;
|
||||
private Recipient recipient;
|
||||
|
||||
public ContactSelectionListItem(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ContactSelectionListItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ContactSelectionListItem(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
this.contactPhotoImage = (ImageView) findViewById(R.id.contact_photo_image);
|
||||
this.numberView = (TextView) findViewById(R.id.number);
|
||||
this.labelView = (TextView) findViewById(R.id.label);
|
||||
this.nameView = (TextView) findViewById(R.id.name);
|
||||
this.checkBox = (CheckBox) findViewById(R.id.check_box);
|
||||
}
|
||||
|
||||
public void set(long id, int type, String name, String number, String label, int color, boolean multiSelect) {
|
||||
this.id = id;
|
||||
this.number = number;
|
||||
|
||||
if (number != null) {
|
||||
this.recipient = RecipientFactory.getRecipientsFromString(getContext(), number, true)
|
||||
.getPrimaryRecipient();
|
||||
}
|
||||
|
||||
this.nameView.setTextColor(color);
|
||||
this.numberView.setTextColor(color);
|
||||
|
||||
setText(type, name, number, label);
|
||||
setContactPhotoImage(recipient);
|
||||
|
||||
if (multiSelect) this.checkBox.setVisibility(View.VISIBLE);
|
||||
else this.checkBox.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setChecked(boolean selected) {
|
||||
this.checkBox.setChecked(selected);
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
if (recipient != null) {
|
||||
recipient.removeListener(this);
|
||||
recipient = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setText(int type, String name, String number, String label) {
|
||||
if (number == null || number.isEmpty()) {
|
||||
this.nameView.setEnabled(false);
|
||||
this.numberView.setText("");
|
||||
this.labelView.setVisibility(View.GONE);
|
||||
} else if (type == ContactsDatabase.PUSH_TYPE) {
|
||||
this.numberView.setText(number);
|
||||
this.nameView.setEnabled(true);
|
||||
this.labelView.setVisibility(View.GONE);
|
||||
} else {
|
||||
this.numberView.setText(number);
|
||||
this.nameView.setEnabled(true);
|
||||
this.labelView.setText(label);
|
||||
this.labelView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
this.nameView.setText(name);
|
||||
}
|
||||
|
||||
private void setContactPhotoImage(@Nullable Recipient recipient) {
|
||||
if (recipient!= null) {
|
||||
contactPhotoImage.setImageDrawable(recipient.getContactPhoto());
|
||||
recipient.addListener(this);
|
||||
} else {
|
||||
contactPhotoImage.setImageDrawable(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient recipient) {
|
||||
if (this.recipient == recipient) {
|
||||
this.contactPhotoImage.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
contactPhotoImage.setImageDrawable(recipient.getContactPhoto());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public long getContactId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user