AccountAdapter.java

  1package eu.siacs.conversations.ui.adapter;
  2
  3import android.content.res.Resources;
  4import android.databinding.DataBindingUtil;
  5import android.graphics.Bitmap;
  6import android.graphics.drawable.BitmapDrawable;
  7import android.graphics.drawable.Drawable;
  8import android.os.AsyncTask;
  9import android.support.annotation.NonNull;
 10import android.view.LayoutInflater;
 11import android.view.View;
 12import android.view.ViewGroup;
 13import android.widget.ArrayAdapter;
 14import android.widget.ImageView;
 15
 16import java.lang.ref.WeakReference;
 17import java.util.List;
 18import java.util.concurrent.RejectedExecutionException;
 19
 20import eu.siacs.conversations.Config;
 21import eu.siacs.conversations.R;
 22import eu.siacs.conversations.databinding.AccountRowBinding;
 23import eu.siacs.conversations.entities.Account;
 24import eu.siacs.conversations.ui.XmppActivity;
 25import eu.siacs.conversations.ui.util.StyledAttributes;
 26import eu.siacs.conversations.utils.UIHelper;
 27
 28public class AccountAdapter extends ArrayAdapter<Account> {
 29
 30    private XmppActivity activity;
 31    private boolean showStateButton;
 32
 33    public AccountAdapter(XmppActivity activity, List<Account> objects, boolean showStateButton) {
 34        super(activity, 0, objects);
 35        this.activity = activity;
 36        this.showStateButton = showStateButton;
 37    }
 38
 39    public AccountAdapter(XmppActivity activity, List<Account> objects) {
 40        super(activity, 0, objects);
 41        this.activity = activity;
 42        this.showStateButton = true;
 43    }
 44
 45    @Override
 46    public View getView(int position, View view, @NonNull ViewGroup parent) {
 47        final Account account = getItem(position);
 48        final ViewHolder viewHolder;
 49        if (view == null) {
 50            AccountRowBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.account_row, parent, false);
 51            view = binding.getRoot();
 52            viewHolder = new ViewHolder(binding);
 53            view.setTag(viewHolder);
 54        } else {
 55            viewHolder = (ViewHolder) view.getTag();
 56        }
 57        if (Config.DOMAIN_LOCK != null) {
 58            viewHolder.binding.accountJid.setText(account.getJid().getLocal());
 59        } else {
 60            viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toString());
 61        }
 62        loadAvatar(account, viewHolder.binding.accountImage);
 63        viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId()));
 64        switch (account.getStatus()) {
 65            case ONLINE:
 66                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline));
 67                break;
 68            case DISABLED:
 69            case CONNECTING:
 70                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary));
 71                break;
 72            default:
 73                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError));
 74                break;
 75        }
 76        final boolean isDisabled = (account.getStatus() == Account.State.DISABLED);
 77        viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener(null);
 78        viewHolder.binding.tglAccountStatus.setChecked(!isDisabled);
 79        if (this.showStateButton) {
 80            viewHolder.binding.tglAccountStatus.setVisibility(View.VISIBLE);
 81        } else {
 82            viewHolder.binding.tglAccountStatus.setVisibility(View.GONE);
 83        }
 84        viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener((compoundButton, b) -> {
 85            if (b == isDisabled && activity instanceof OnTglAccountState) {
 86                ((OnTglAccountState) activity).onClickTglAccountState(account, b);
 87            }
 88        });
 89        return view;
 90    }
 91
 92    private static class ViewHolder {
 93        private final AccountRowBinding binding;
 94
 95        private ViewHolder(AccountRowBinding binding) {
 96            this.binding = binding;
 97        }
 98    }
 99
100    class BitmapWorkerTask extends AsyncTask<Account, Void, Bitmap> {
101        private final WeakReference<ImageView> imageViewReference;
102        private Account account = null;
103
104        public BitmapWorkerTask(ImageView imageView) {
105            imageViewReference = new WeakReference<>(imageView);
106        }
107
108        @Override
109        protected Bitmap doInBackground(Account... params) {
110            this.account = params[0];
111            return activity.avatarService().get(this.account, activity.getPixel(48), isCancelled());
112        }
113
114        @Override
115        protected void onPostExecute(Bitmap bitmap) {
116            if (bitmap != null && !isCancelled()) {
117                final ImageView imageView = imageViewReference.get();
118                if (imageView != null) {
119                    imageView.setImageBitmap(bitmap);
120                    imageView.setBackgroundColor(0x00000000);
121                }
122            }
123        }
124    }
125
126    public void loadAvatar(Account account, ImageView imageView) {
127        if (cancelPotentialWork(account, imageView)) {
128            final Bitmap bm = activity.avatarService().get(account, activity.getPixel(48), true);
129            if (bm != null) {
130                cancelPotentialWork(account, imageView);
131                imageView.setImageBitmap(bm);
132                imageView.setBackgroundColor(0x00000000);
133            } else {
134                imageView.setBackgroundColor(UIHelper.getColorForName(account.getJid().asBareJid().toString()));
135                imageView.setImageDrawable(null);
136                final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
137                final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
138                imageView.setImageDrawable(asyncDrawable);
139                try {
140                    task.execute(account);
141                } catch (final RejectedExecutionException ignored) {
142                }
143            }
144        }
145    }
146
147
148    public interface OnTglAccountState {
149        void onClickTglAccountState(Account account, boolean state);
150    }
151
152    public static boolean cancelPotentialWork(Account account, ImageView imageView) {
153        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
154
155        if (bitmapWorkerTask != null) {
156            final Account oldAccount = bitmapWorkerTask.account;
157            if (oldAccount == null || account != oldAccount) {
158                bitmapWorkerTask.cancel(true);
159            } else {
160                return false;
161            }
162        }
163        return true;
164    }
165
166    private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
167        if (imageView != null) {
168            final Drawable drawable = imageView.getDrawable();
169            if (drawable instanceof AsyncDrawable) {
170                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
171                return asyncDrawable.getBitmapWorkerTask();
172            }
173        }
174        return null;
175    }
176
177    static class AsyncDrawable extends BitmapDrawable {
178        private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
179
180        public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
181            super(res, bitmap);
182            bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
183        }
184
185        public BitmapWorkerTask getBitmapWorkerTask() {
186            return bitmapWorkerTaskReference.get();
187        }
188    }
189}