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