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