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