ConversationAdapter.java

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