ConversationAdapter.java

  1package eu.siacs.conversations.ui.adapter;
  2
  3import android.content.res.ColorStateList;
  4import android.graphics.Typeface;
  5import android.util.Pair;
  6import android.view.LayoutInflater;
  7import android.view.View;
  8import android.view.ViewGroup;
  9
 10import androidx.annotation.DrawableRes;
 11import androidx.annotation.NonNull;
 12import androidx.core.widget.ImageViewCompat;
 13import androidx.databinding.DataBindingUtil;
 14import androidx.recyclerview.widget.RecyclerView;
 15
 16import com.google.android.material.color.MaterialColors;
 17import com.google.common.base.Optional;
 18
 19import eu.siacs.conversations.R;
 20import eu.siacs.conversations.databinding.ItemConversationBinding;
 21import eu.siacs.conversations.entities.Conversation;
 22import eu.siacs.conversations.entities.Conversational;
 23import eu.siacs.conversations.entities.Message;
 24import eu.siacs.conversations.ui.ConversationFragment;
 25import eu.siacs.conversations.ui.XmppActivity;
 26import eu.siacs.conversations.ui.util.Attachment;
 27import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 28import eu.siacs.conversations.utils.IrregularUnicodeDetector;
 29import eu.siacs.conversations.utils.UIHelper;
 30import eu.siacs.conversations.xmpp.Jid;
 31import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
 32
 33import java.util.List;
 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.item_conversation,
 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 (conversation == ConversationFragment.getConversation(activity)) {
 73            viewHolder.binding.frame.setBackgroundResource(
 74                    R.drawable.background_selected_item_conversation);
 75            // viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurfaceDim));
 76        } else {
 77            viewHolder.binding.frame.setBackgroundColor(
 78                    MaterialColors.getColor(
 79                            viewHolder.binding.frame,
 80                            com.google.android.material.R.attr.colorSurface));
 81        }
 82
 83        final Message message = conversation.getLatestMessage();
 84        final int status = message.getStatus();
 85        final int unreadCount = conversation.unreadCount();
 86        final boolean isRead = conversation.isRead();
 87        final @DrawableRes Integer messageStatusDrawable =
 88                MessageAdapter.getMessageStatusAsDrawable(message, status);
 89        if (message.getType() == Message.TYPE_RTP_SESSION) {
 90            viewHolder.binding.messageStatus.setVisibility(View.GONE);
 91        } else if (messageStatusDrawable == null) {
 92            if (status <= Message.STATUS_RECEIVED) {
 93                viewHolder.binding.messageStatus.setVisibility(View.GONE);
 94            } else {
 95                viewHolder.binding.messageStatus.setVisibility(View.INVISIBLE);
 96            }
 97        } else {
 98            viewHolder.binding.messageStatus.setImageResource(messageStatusDrawable);
 99            if (status == Message.STATUS_SEND_DISPLAYED) {
100                viewHolder.binding.messageStatus.setImageResource(R.drawable.ic_done_all_bold_24dp);
101                ImageViewCompat.setImageTintList(
102                        viewHolder.binding.messageStatus,
103                        ColorStateList.valueOf(
104                                MaterialColors.getColor(
105                                        viewHolder.binding.messageStatus,
106                                        com.google.android.material.R.attr.colorPrimary)));
107            } else {
108                ImageViewCompat.setImageTintList(
109                        viewHolder.binding.messageStatus,
110                        ColorStateList.valueOf(
111                                MaterialColors.getColor(
112                                        viewHolder.binding.messageStatus,
113                                        com.google.android.material.R.attr.colorControlNormal)));
114            }
115            viewHolder.binding.messageStatus.setVisibility(View.VISIBLE);
116        }
117        final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
118        if (unreadCount > 0) {
119            viewHolder.binding.unreadCount.setVisibility(View.VISIBLE);
120            viewHolder.binding.unreadCount.setUnreadCount(unreadCount);
121        } else {
122            viewHolder.binding.unreadCount.setVisibility(View.GONE);
123        }
124
125        if (isRead) {
126            viewHolder.binding.conversationName.setTypeface(null, Typeface.NORMAL);
127        } else {
128            viewHolder.binding.conversationName.setTypeface(null, Typeface.BOLD);
129        }
130
131        if (draft != null) {
132            viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
133            viewHolder.binding.conversationLastmsg.setText(draft.getMessage());
134            viewHolder.binding.senderName.setText(R.string.draft);
135            viewHolder.binding.senderName.setVisibility(View.VISIBLE);
136            viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
137            viewHolder.binding.senderName.setTypeface(null, Typeface.ITALIC);
138        } else {
139            final boolean fileAvailable = !message.isDeleted();
140            final boolean showPreviewText;
141            if (fileAvailable
142                    && (message.isFileOrImage()
143                            || message.treatAsDownloadable()
144                            || message.isGeoUri())) {
145                final var attachment = Attachment.of(message);
146                final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
147                showPreviewText = false;
148                viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
149                viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
150            } else {
151                viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
152                showPreviewText = true;
153            }
154            final Pair<CharSequence, Boolean> preview =
155                    UIHelper.getMessagePreview(
156                            activity,
157                            message,
158                            viewHolder.binding.conversationLastmsg.getCurrentTextColor());
159            if (showPreviewText) {
160                viewHolder.binding.conversationLastmsg.setText(UIHelper.shorten(preview.first));
161            } else {
162                viewHolder.binding.conversationLastmsgImg.setContentDescription(preview.first);
163            }
164            viewHolder.binding.conversationLastmsg.setVisibility(
165                    showPreviewText ? View.VISIBLE : View.GONE);
166            if (preview.second) {
167                if (isRead) {
168                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.ITALIC);
169                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
170                } else {
171                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD_ITALIC);
172                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
173                }
174            } else {
175                if (isRead) {
176                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
177                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
178                } else {
179                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD);
180                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
181                }
182            }
183            if (status == Message.STATUS_RECEIVED) {
184                if (conversation.getMode() == Conversation.MODE_MULTI) {
185                    viewHolder.binding.senderName.setVisibility(View.VISIBLE);
186                    String display = UIHelper.getMessageDisplayName(message);
187                    // Skip when nickname only consists of blank chars
188                    if (display.split("\\s+").length != 0)
189                        display = display.split("\\s+")[0];
190                    viewHolder.binding.senderName.setText(display + ':');
191                } else {
192                    viewHolder.binding.senderName.setVisibility(View.GONE);
193                }
194            } else if (message.getType() != Message.TYPE_STATUS) {
195                viewHolder.binding.senderName.setVisibility(View.VISIBLE);
196                viewHolder.binding.senderName.setText(activity.getString(R.string.me) + ':');
197            } else {
198                viewHolder.binding.senderName.setVisibility(View.GONE);
199            }
200        }
201
202        final Optional<OngoingRtpSession> ongoingCall;
203        if (conversation.getMode() == Conversational.MODE_MULTI) {
204            ongoingCall = Optional.absent();
205        } else {
206            ongoingCall =
207                    activity.xmppConnectionService
208                            .getJingleConnectionManager()
209                            .getOngoingRtpConnection(conversation.getContact());
210        }
211
212        if (ongoingCall.isPresent()) {
213            viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
214            viewHolder.binding.notificationStatus.setImageResource(
215                    R.drawable.ic_phone_in_talk_24dp);
216        } else {
217            final long muted_till =
218                    conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
219            if (muted_till == Long.MAX_VALUE) {
220                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
221                viewHolder.binding.notificationStatus.setImageResource(
222                        R.drawable.ic_notifications_off_24dp);
223            } else if (muted_till >= System.currentTimeMillis()) {
224                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
225                viewHolder.binding.notificationStatus.setImageResource(
226                        R.drawable.ic_notifications_paused_24dp);
227            } else if (conversation.alwaysNotify()) {
228                viewHolder.binding.notificationStatus.setVisibility(View.GONE);
229            } else {
230                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
231                viewHolder.binding.notificationStatus.setImageResource(
232                        R.drawable.ic_notifications_none_24dp);
233            }
234        }
235
236        long timestamp;
237        if (draft != null) {
238            timestamp = draft.getTimestamp();
239        } else {
240            timestamp = conversation.getLatestMessage().getTimeSent();
241        }
242        viewHolder.binding.pinnedOnTop.setVisibility(
243                conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false)
244                        ? View.VISIBLE
245                        : View.GONE);
246        viewHolder.binding.conversationLastupdate.setText(
247                UIHelper.readableTimeDifference(activity, timestamp));
248        AvatarWorkerTask.loadAvatar(
249                conversation,
250                viewHolder.binding.conversationImage,
251                R.dimen.avatar_on_conversation_overview);
252        viewHolder.itemView.setOnClickListener(v -> listener.onConversationClick(v, conversation));
253    }
254
255    @Override
256    public int getItemCount() {
257        return conversations.size();
258    }
259
260    public void setConversationClickListener(OnConversationClickListener listener) {
261        this.listener = listener;
262    }
263
264    public void insert(Conversation c, int position) {
265        conversations.add(position, c);
266        notifyDataSetChanged();
267    }
268
269    public void remove(Conversation conversation, int position) {
270        conversations.remove(conversation);
271        notifyItemRemoved(position);
272    }
273
274    public interface OnConversationClickListener {
275        void onConversationClick(View view, Conversation conversation);
276    }
277
278    public static class ConversationViewHolder extends RecyclerView.ViewHolder {
279        public final ItemConversationBinding binding;
280
281        private ConversationViewHolder(final ItemConversationBinding binding) {
282            super(binding.getRoot());
283            this.binding = binding;
284        }
285    }
286}