BackupFileAdapter.java

  1package eu.siacs.conversations.ui.adapter;
  2
  3import android.content.res.Resources;
  4import android.graphics.Bitmap;
  5import android.graphics.drawable.BitmapDrawable;
  6import android.graphics.drawable.Drawable;
  7import android.os.AsyncTask;
  8import android.text.format.DateUtils;
  9import android.util.DisplayMetrics;
 10import android.view.LayoutInflater;
 11import android.view.View;
 12import android.view.ViewGroup;
 13import android.widget.ImageView;
 14import androidx.annotation.NonNull;
 15import androidx.databinding.DataBindingUtil;
 16import androidx.recyclerview.widget.RecyclerView;
 17import eu.siacs.conversations.R;
 18import eu.siacs.conversations.databinding.ItemAccountBinding;
 19import eu.siacs.conversations.services.AvatarService;
 20import eu.siacs.conversations.utils.BackupFile;
 21import eu.siacs.conversations.utils.BackupFileHeader;
 22import eu.siacs.conversations.utils.UIHelper;
 23import eu.siacs.conversations.xmpp.Jid;
 24import java.lang.ref.WeakReference;
 25import java.util.ArrayList;
 26import java.util.List;
 27import java.util.concurrent.RejectedExecutionException;
 28
 29public class BackupFileAdapter
 30        extends RecyclerView.Adapter<BackupFileAdapter.BackupFileViewHolder> {
 31
 32    private OnItemClickedListener listener;
 33
 34    private final List<BackupFile> files = new ArrayList<>();
 35
 36    @NonNull
 37    @Override
 38    public BackupFileViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
 39        return new BackupFileViewHolder(
 40                DataBindingUtil.inflate(
 41                        LayoutInflater.from(viewGroup.getContext()),
 42                        R.layout.item_account,
 43                        viewGroup,
 44                        false));
 45    }
 46
 47    @Override
 48    public void onBindViewHolder(@NonNull BackupFileViewHolder backupFileViewHolder, int position) {
 49        final BackupFile backupFile = files.get(position);
 50        final BackupFileHeader header = backupFile.getHeader();
 51        backupFileViewHolder.binding.accountJid.setText(header.getJid().asBareJid().toString());
 52        backupFileViewHolder.binding.accountStatus.setText(
 53                String.format(
 54                        "%s · %s",
 55                        header.getApp(),
 56                        DateUtils.formatDateTime(
 57                                backupFileViewHolder.binding.getRoot().getContext(),
 58                                header.getTimestamp(),
 59                                DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR)));
 60        backupFileViewHolder.binding.tglAccountStatus.setVisibility(View.GONE);
 61        backupFileViewHolder
 62                .binding
 63                .getRoot()
 64                .setOnClickListener(
 65                        v -> {
 66                            if (listener != null) {
 67                                listener.onClick(backupFile);
 68                            }
 69                        });
 70        loadAvatar(header.getJid(), backupFileViewHolder.binding.accountImage);
 71    }
 72
 73    @Override
 74    public int getItemCount() {
 75        return files.size();
 76    }
 77
 78    public void setFiles(List<BackupFile> files) {
 79        this.files.clear();
 80        this.files.addAll(files);
 81        notifyDataSetChanged();
 82    }
 83
 84    public void setOnItemClickedListener(OnItemClickedListener listener) {
 85        this.listener = listener;
 86    }
 87
 88    static class BackupFileViewHolder extends RecyclerView.ViewHolder {
 89        private final ItemAccountBinding binding;
 90
 91        BackupFileViewHolder(ItemAccountBinding binding) {
 92            super(binding.getRoot());
 93            this.binding = binding;
 94        }
 95    }
 96
 97    public interface OnItemClickedListener {
 98        void onClick(BackupFile backupFile);
 99    }
100
101    static class BitmapWorkerTask extends AsyncTask<Jid, Void, Bitmap> {
102        private final WeakReference<ImageView> imageViewReference;
103        private Jid jid = null;
104        private final int size;
105
106        BitmapWorkerTask(final ImageView imageView) {
107            imageViewReference = new WeakReference<>(imageView);
108            DisplayMetrics metrics = imageView.getContext().getResources().getDisplayMetrics();
109            this.size = ((int) (48 * metrics.density));
110        }
111
112        @Override
113        protected Bitmap doInBackground(Jid... params) {
114            this.jid = params[0];
115            return AvatarService.get(this.jid, size);
116        }
117
118        @Override
119        protected void onPostExecute(Bitmap bitmap) {
120            if (bitmap != null && !isCancelled()) {
121                final ImageView imageView = imageViewReference.get();
122                if (imageView != null) {
123                    imageView.setImageBitmap(bitmap);
124                    imageView.setBackgroundColor(0x00000000);
125                }
126            }
127        }
128    }
129
130    private void loadAvatar(Jid jid, ImageView imageView) {
131        if (cancelPotentialWork(jid, imageView)) {
132            imageView.setBackgroundColor(UIHelper.getColorForName(jid.asBareJid().toString()));
133            imageView.setImageDrawable(null);
134            final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
135            final AsyncDrawable asyncDrawable =
136                    new AsyncDrawable(imageView.getContext().getResources(), null, task);
137            imageView.setImageDrawable(asyncDrawable);
138            try {
139                task.execute(jid);
140            } catch (final RejectedExecutionException ignored) {
141            }
142        }
143    }
144
145    private static boolean cancelPotentialWork(Jid jid, ImageView imageView) {
146        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
147
148        if (bitmapWorkerTask != null) {
149            final Jid oldJid = bitmapWorkerTask.jid;
150            if (oldJid == null || jid != oldJid) {
151                bitmapWorkerTask.cancel(true);
152            } else {
153                return false;
154            }
155        }
156        return true;
157    }
158
159    private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
160        if (imageView != null) {
161            final Drawable drawable = imageView.getDrawable();
162            if (drawable instanceof AsyncDrawable asyncDrawable) {
163                return asyncDrawable.getBitmapWorkerTask();
164            }
165        }
166        return null;
167    }
168
169    static class AsyncDrawable extends BitmapDrawable {
170        private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
171
172        AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
173            super(res, bitmap);
174            bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
175        }
176
177        BitmapWorkerTask getBitmapWorkerTask() {
178            return bitmapWorkerTaskReference.get();
179        }
180    }
181}