ConversationAdapter.java

  1package eu.siacs.conversations.ui.adapter;
  2
  3import android.graphics.Typeface;
  4import android.util.Pair;
  5import android.view.MenuItem;
  6import android.view.LayoutInflater;
  7import android.view.View;
  8import android.view.ViewGroup;
  9
 10import androidx.annotation.NonNull;
 11import androidx.core.graphics.ColorUtils;
 12import androidx.databinding.DataBindingUtil;
 13import androidx.recyclerview.widget.RecyclerView;
 14
 15import com.google.common.base.Optional;
 16import com.google.common.base.Strings;
 17
 18import java.util.List;
 19
 20import eu.siacs.conversations.R;
 21import eu.siacs.conversations.databinding.ConversationListRowBinding;
 22import eu.siacs.conversations.entities.Conversation;
 23import eu.siacs.conversations.entities.Conversational;
 24import eu.siacs.conversations.entities.Message;
 25import eu.siacs.conversations.ui.ConversationFragment;
 26import eu.siacs.conversations.ui.XmppActivity;
 27import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 28import eu.siacs.conversations.ui.util.StyledAttributes;
 29import eu.siacs.conversations.utils.IrregularUnicodeDetector;
 30import eu.siacs.conversations.utils.MimeUtils;
 31import eu.siacs.conversations.utils.UIHelper;
 32import eu.siacs.conversations.xmpp.Jid;
 33import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
 34
 35public class ConversationAdapter
 36        extends RecyclerView.Adapter<ConversationAdapter.ConversationViewHolder> {
 37
 38    private final XmppActivity activity;
 39    private final List<Conversation> conversations;
 40    private OnConversationClickListener listener;
 41
 42    public ConversationAdapter(XmppActivity activity, List<Conversation> conversations) {
 43        this.activity = activity;
 44        this.conversations = conversations;
 45    }
 46
 47    @NonNull
 48    @Override
 49    public ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 50        return new ConversationViewHolder(
 51                DataBindingUtil.inflate(
 52                        LayoutInflater.from(parent.getContext()),
 53                        R.layout.conversation_list_row,
 54                        parent,
 55                        false));
 56    }
 57
 58    @Override
 59    public void onBindViewHolder(@NonNull ConversationViewHolder viewHolder, int position) {
 60        Conversation conversation = conversations.get(position);
 61        if (conversation == null) {
 62            return;
 63        }
 64        CharSequence name = conversation.getName();
 65        if (name instanceof Jid) {
 66            viewHolder.binding.conversationName.setText(
 67                    IrregularUnicodeDetector.style(activity, (Jid) name));
 68        } else {
 69            viewHolder.binding.conversationName.setText(name);
 70        }
 71
 72        if (activity.xmppConnectionService != null && activity.xmppConnectionService.getAccounts().size() > 1) {
 73            viewHolder.binding.frame.setBackgroundColor(conversation.getAccount().getColor(activity.isDarkTheme()));
 74        }
 75
 76        Message message = conversation.getLatestMessage();
 77        final int unreadCount = conversation.unreadCount();
 78        final boolean isRead = conversation.isRead();
 79        final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
 80        if (unreadCount > 0) {
 81            viewHolder.binding.unreadCount.setVisibility(View.VISIBLE);
 82            viewHolder.binding.unreadCount.setUnreadCount(unreadCount);
 83        } else {
 84            viewHolder.binding.unreadCount.setVisibility(View.GONE);
 85        }
 86
 87        if (isRead) {
 88            viewHolder.binding.conversationName.setTypeface(null, Typeface.NORMAL);
 89        } else {
 90            viewHolder.binding.conversationName.setTypeface(null, Typeface.BOLD);
 91        }
 92
 93        if (draft != null) {
 94            viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
 95            viewHolder.binding.conversationLastmsg.setText(draft.getMessage());
 96            viewHolder.binding.senderName.setText(R.string.draft);
 97            viewHolder.binding.senderName.setVisibility(View.VISIBLE);
 98            viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
 99            viewHolder.binding.senderName.setTypeface(null, Typeface.ITALIC);
100        } else {
101            final boolean fileAvailable = !message.isDeleted();
102            final boolean showPreviewText;
103            if (fileAvailable
104                    && (message.isFileOrImage()
105                            || message.treatAsDownloadable()
106                            || message.isGeoUri())) {
107                final int imageResource;
108                if (message.isGeoUri()) {
109                    imageResource =
110                            activity.getThemeResource(
111                                    R.attr.ic_attach_location, R.drawable.ic_attach_location);
112                    showPreviewText = false;
113                } else {
114                    // TODO move this into static MediaPreview method and use same icons as in
115                    // MediaAdapter
116                    final String mime = message.getMimeType();
117                    if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) {
118                        final Message.FileParams fileParams = message.getFileParams();
119                        if (fileParams.width > 0 && fileParams.height > 0) {
120                            imageResource =
121                                    activity.getThemeResource(
122                                            R.attr.ic_attach_videocam,
123                                            R.drawable.ic_attach_videocam);
124                            showPreviewText = false;
125                        } else if (fileParams.runtime > 0) {
126                            imageResource =
127                                    activity.getThemeResource(
128                                            R.attr.ic_attach_record, R.drawable.ic_attach_record);
129                            showPreviewText = false;
130                        } else {
131                            imageResource =
132                                    activity.getThemeResource(
133                                            R.attr.ic_attach_document,
134                                            R.drawable.ic_attach_document);
135                            showPreviewText = true;
136                        }
137                    } else {
138                        switch (Strings.nullToEmpty(mime).split("/")[0]) {
139                            case "image":
140                                imageResource =
141                                        activity.getThemeResource(
142                                                R.attr.ic_attach_photo, R.drawable.ic_attach_photo);
143                                showPreviewText = false;
144                                break;
145                            case "video":
146                                imageResource =
147                                        activity.getThemeResource(
148                                                R.attr.ic_attach_videocam,
149                                                R.drawable.ic_attach_videocam);
150                                showPreviewText = false;
151                                break;
152                            case "audio":
153                                imageResource =
154                                        activity.getThemeResource(
155                                                R.attr.ic_attach_record,
156                                                R.drawable.ic_attach_record);
157                                showPreviewText = false;
158                                break;
159                            default:
160                                imageResource =
161                                        activity.getThemeResource(
162                                                R.attr.ic_attach_document,
163                                                R.drawable.ic_attach_document);
164                                showPreviewText = true;
165                                break;
166                        }
167                    }
168                }
169                viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
170                viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
171            } else {
172                viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
173                showPreviewText = true;
174            }
175            final Pair<CharSequence, Boolean> preview =
176                    UIHelper.getMessagePreview(
177                            activity,
178                            message,
179                            viewHolder.binding.conversationLastmsg.getCurrentTextColor());
180            if (showPreviewText) {
181                viewHolder.binding.conversationLastmsg.setText(UIHelper.shorten(preview.first));
182            } else {
183                viewHolder.binding.conversationLastmsgImg.setContentDescription(preview.first);
184            }
185            viewHolder.binding.conversationLastmsg.setVisibility(
186                    showPreviewText ? View.VISIBLE : View.GONE);
187            if (preview.second) {
188                if (isRead) {
189                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.ITALIC);
190                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
191                } else {
192                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD_ITALIC);
193                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
194                }
195            } else {
196                if (isRead) {
197                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
198                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
199                } else {
200                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD);
201                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
202                }
203            }
204            if (message.getStatus() == Message.STATUS_RECEIVED) {
205                if (conversation.getMode() == Conversation.MODE_MULTI) {
206                    viewHolder.binding.senderName.setVisibility(View.VISIBLE);
207                    final String dname = UIHelper.getMessageDisplayName(message);
208                    final String[] words = dname.split("\\s+");
209                    viewHolder.binding.senderName.setText((words.length > 0 ? words[0] : dname) + ':');
210                } else {
211                    viewHolder.binding.senderName.setVisibility(View.GONE);
212                }
213            } else if (message.getType() != Message.TYPE_STATUS) {
214                viewHolder.binding.senderName.setVisibility(View.VISIBLE);
215                viewHolder.binding.senderName.setText(activity.getString(R.string.me) + ':');
216            } else {
217                viewHolder.binding.senderName.setVisibility(View.GONE);
218            }
219        }
220
221        final Optional<OngoingRtpSession> ongoingCall;
222        if (conversation.getMode() == Conversational.MODE_MULTI) {
223            ongoingCall = Optional.absent();
224        } else {
225            ongoingCall =
226                    activity.xmppConnectionService
227                            .getJingleConnectionManager()
228                            .getOngoingRtpConnection(conversation.getContact());
229        }
230
231        if (ongoingCall.isPresent()) {
232            viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
233            final int ic_ongoing_call =
234                    activity.getThemeResource(
235                            R.attr.ic_ongoing_call_hint, R.drawable.ic_phone_in_talk_black_18dp);
236            viewHolder.binding.notificationStatus.setImageResource(ic_ongoing_call);
237        } else {
238            final long muted_till =
239                    conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
240            if (muted_till == Long.MAX_VALUE) {
241                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
242                int ic_notifications_off =
243                        activity.getThemeResource(
244                                R.attr.icon_notifications_off,
245                                R.drawable.ic_notifications_off_black_24dp);
246                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_off);
247            } else if (muted_till >= System.currentTimeMillis()) {
248                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
249                int ic_notifications_paused =
250                        activity.getThemeResource(
251                                R.attr.icon_notifications_paused,
252                                R.drawable.ic_notifications_paused_black_24dp);
253                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_paused);
254            } else if (conversation.alwaysNotify()) {
255                viewHolder.binding.notificationStatus.setVisibility(View.GONE);
256            } else {
257                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
258                int ic_notifications_none =
259                        activity.getThemeResource(
260                                R.attr.icon_notifications_none,
261                                R.drawable.ic_notifications_none_black_24dp);
262                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_none);
263            }
264        }
265
266        long timestamp;
267        if (draft != null) {
268            timestamp = draft.getTimestamp();
269        } else {
270            timestamp = conversation.getLatestMessage().getTimeSent();
271        }
272        viewHolder.binding.pinnedOnTop.setVisibility(
273                conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false)
274                        ? View.VISIBLE
275                        : View.GONE);
276        viewHolder.binding.conversationLastupdate.setText(
277                UIHelper.readableTimeDifference(activity, timestamp));
278        AvatarWorkerTask.loadAvatar(
279                conversation,
280                viewHolder.binding.conversationImage,
281                R.dimen.avatar_on_conversation_overview);
282        viewHolder.itemView.setOnClickListener(v -> listener.onConversationClick(v, conversation));
283    }
284
285    @Override
286    public int getItemCount() {
287        return conversations.size();
288    }
289
290    public void setConversationClickListener(OnConversationClickListener listener) {
291        this.listener = listener;
292    }
293
294    public void insert(Conversation c, int position) {
295        conversations.add(position, c);
296        notifyDataSetChanged();
297    }
298
299    public void remove(Conversation conversation, int position) {
300        conversations.remove(conversation);
301        notifyItemRemoved(position);
302    }
303
304    public interface OnConversationClickListener {
305        void onConversationClick(View view, Conversation conversation);
306    }
307
308    static class ConversationViewHolder extends RecyclerView.ViewHolder {
309        private final ConversationListRowBinding binding;
310
311        private ConversationViewHolder(ConversationListRowBinding binding) {
312            super(binding.getRoot());
313            this.binding = binding;
314            binding.getRoot().setLongClickable(true);
315        }
316    }
317}