1package eu.siacs.conversations.ui.adapter;
2
3import android.content.Context;
4import android.content.res.Resources;
5import android.databinding.DataBindingUtil;
6import android.graphics.Bitmap;
7import android.graphics.drawable.BitmapDrawable;
8import android.graphics.drawable.Drawable;
9import android.os.AsyncTask;
10import android.support.annotation.NonNull;
11import android.support.v7.widget.RecyclerView;
12import android.view.LayoutInflater;
13import android.view.ViewGroup;
14import android.widget.ImageView;
15
16import java.lang.ref.WeakReference;
17import java.util.ArrayList;
18import java.util.List;
19import java.util.concurrent.RejectedExecutionException;
20
21import eu.siacs.conversations.R;
22import eu.siacs.conversations.databinding.MediaPreviewBinding;
23import eu.siacs.conversations.ui.ConversationFragment;
24import eu.siacs.conversations.ui.XmppActivity;
25import eu.siacs.conversations.ui.util.Attachment;
26
27public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapter.MediaPreviewViewHolder> {
28
29 private final ArrayList<Attachment> mediaPreviews = new ArrayList<>();
30
31 private final ConversationFragment conversationFragment;
32
33 public MediaPreviewAdapter(ConversationFragment fragment) {
34 this.conversationFragment = fragment;
35 }
36
37 @NonNull
38 @Override
39 public MediaPreviewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
40 LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
41 MediaPreviewBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media_preview, parent, false);
42 return new MediaPreviewViewHolder(binding);
43 }
44
45 @Override
46 public void onBindViewHolder(@NonNull MediaPreviewViewHolder holder, int position) {
47 final Context context = conversationFragment.getActivity();
48 final Attachment attachment = mediaPreviews.get(position);
49 if (attachment.renderThumbnail()) {
50 holder.binding.mediaPreview.setImageAlpha(255);
51 loadPreview(attachment, holder.binding.mediaPreview);
52 } else {
53 cancelPotentialWork(attachment, holder.binding.mediaPreview);
54 MediaAdapter.renderPreview(context, attachment, holder.binding.mediaPreview);
55 }
56 holder.binding.deleteButton.setOnClickListener(v -> {
57 int pos = mediaPreviews.indexOf(attachment);
58 mediaPreviews.remove(pos);
59 notifyItemRemoved(pos);
60 conversationFragment.toggleInputMethod();
61 });
62 }
63
64 public void addMediaPreviews(List<Attachment> attachments) {
65 this.mediaPreviews.addAll(attachments);
66 notifyDataSetChanged();
67 }
68
69 private void loadPreview(Attachment attachment, ImageView imageView) {
70 if (cancelPotentialWork(attachment, imageView)) {
71 XmppActivity activity = (XmppActivity) conversationFragment.getActivity();
72 final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment,Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)),true);
73 if (bm != null) {
74 cancelPotentialWork(attachment, imageView);
75 imageView.setImageBitmap(bm);
76 imageView.setBackgroundColor(0x00000000);
77 } else {
78 imageView.setBackgroundColor(0xff333333);
79 imageView.setImageDrawable(null);
80 final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
81 final AsyncDrawable asyncDrawable = new AsyncDrawable(conversationFragment.getActivity().getResources(), null, task);
82 imageView.setImageDrawable(asyncDrawable);
83 try {
84 task.execute(attachment);
85 } catch (final RejectedExecutionException ignored) {
86 }
87 }
88 }
89 }
90
91 private static boolean cancelPotentialWork(Attachment attachment, ImageView imageView) {
92 final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
93
94 if (bitmapWorkerTask != null) {
95 final Attachment oldAttachment = bitmapWorkerTask.attachment;
96 if (oldAttachment == null || !oldAttachment.equals(attachment)) {
97 bitmapWorkerTask.cancel(true);
98 } else {
99 return false;
100 }
101 }
102 return true;
103 }
104
105 private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
106 if (imageView != null) {
107 final Drawable drawable = imageView.getDrawable();
108 if (drawable instanceof AsyncDrawable) {
109 final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
110 return asyncDrawable.getBitmapWorkerTask();
111 }
112 }
113 return null;
114 }
115
116 @Override
117 public int getItemCount() {
118 return mediaPreviews.size();
119 }
120
121 public boolean hasAttachments() {
122 return mediaPreviews.size() > 0;
123 }
124
125 public ArrayList<Attachment> getAttachments() {
126 return mediaPreviews;
127 }
128
129 public void clearPreviews() {
130 this.mediaPreviews.clear();
131 }
132
133 class MediaPreviewViewHolder extends RecyclerView.ViewHolder {
134
135 private final MediaPreviewBinding binding;
136
137 MediaPreviewViewHolder(MediaPreviewBinding binding) {
138 super(binding.getRoot());
139 this.binding = binding;
140 }
141 }
142
143 static class AsyncDrawable extends BitmapDrawable {
144 private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
145
146 AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
147 super(res, bitmap);
148 bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
149 }
150
151 BitmapWorkerTask getBitmapWorkerTask() {
152 return bitmapWorkerTaskReference.get();
153 }
154 }
155
156 private static class BitmapWorkerTask extends AsyncTask<Attachment, Void, Bitmap> {
157 private final WeakReference<ImageView> imageViewReference;
158 private Attachment attachment = null;
159
160 BitmapWorkerTask(ImageView imageView) {
161 imageViewReference = new WeakReference<>(imageView);
162 }
163
164 @Override
165 protected Bitmap doInBackground(Attachment... params) {
166 this.attachment = params[0];
167 final XmppActivity activity = XmppActivity.find(imageViewReference);
168 if (activity == null) {
169 return null;
170 }
171 return activity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)), false);
172 }
173
174 @Override
175 protected void onPostExecute(Bitmap bitmap) {
176 if (bitmap != null && !isCancelled()) {
177 final ImageView imageView = imageViewReference.get();
178 if (imageView != null) {
179 imageView.setImageBitmap(bitmap);
180 imageView.setBackgroundColor(0x00000000);
181 }
182 }
183 }
184 }
185}