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 (messageStatusDrawable == null) {
 90            if (status <= Message.STATUS_RECEIVED) {
 91                viewHolder.binding.messageStatus.setVisibility(View.GONE);
 92            } else {
 93                viewHolder.binding.messageStatus.setVisibility(View.INVISIBLE);
 94            }
 95        } else {
 96            viewHolder.binding.messageStatus.setImageResource(messageStatusDrawable);
 97            if (status == Message.STATUS_SEND_DISPLAYED) {
 98                ImageViewCompat.setImageTintList(
 99                        viewHolder.binding.messageStatus,
100                        ColorStateList.valueOf(
101                                MaterialColors.getColor(
102                                        viewHolder.binding.messageStatus,
103                                        com.google.android.material.R.attr.colorPrimary)));
104            } else {
105                ImageViewCompat.setImageTintList(
106                        viewHolder.binding.messageStatus,
107                        ColorStateList.valueOf(
108                                MaterialColors.getColor(
109                                        viewHolder.binding.messageStatus,
110                                        com.google.android.material.R.attr.colorControlNormal)));
111            }
112            viewHolder.binding.messageStatus.setVisibility(View.VISIBLE);
113        }
114        final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
115        if (unreadCount > 0) {
116            viewHolder.binding.unreadCount.setVisibility(View.VISIBLE);
117            viewHolder.binding.unreadCount.setUnreadCount(unreadCount);
118        } else {
119            viewHolder.binding.unreadCount.setVisibility(View.GONE);
120        }
121
122        if (isRead) {
123            viewHolder.binding.conversationName.setTypeface(null, Typeface.NORMAL);
124        } else {
125            viewHolder.binding.conversationName.setTypeface(null, Typeface.BOLD);
126        }
127
128        if (draft != null) {
129            viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
130            viewHolder.binding.conversationLastmsg.setText(draft.getMessage());
131            viewHolder.binding.senderName.setText(R.string.draft);
132            viewHolder.binding.senderName.setVisibility(View.VISIBLE);
133            viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
134            viewHolder.binding.senderName.setTypeface(null, Typeface.ITALIC);
135        } else {
136            final boolean fileAvailable = !message.isDeleted();
137            final boolean showPreviewText;
138            if (fileAvailable
139                    && (message.isFileOrImage()
140                            || message.treatAsDownloadable()
141                            || message.isGeoUri())) {
142                final var attachment = Attachment.of(message);
143                final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
144                showPreviewText = false;
145                viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
146                viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
147            } else {
148                viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
149                showPreviewText = true;
150            }
151            final Pair<CharSequence, Boolean> preview =
152                    UIHelper.getMessagePreview(
153                            activity,
154                            message,
155                            viewHolder.binding.conversationLastmsg.getCurrentTextColor());
156            if (showPreviewText) {
157                viewHolder.binding.conversationLastmsg.setText(UIHelper.shorten(preview.first));
158            } else {
159                viewHolder.binding.conversationLastmsgImg.setContentDescription(preview.first);
160            }
161            viewHolder.binding.conversationLastmsg.setVisibility(
162                    showPreviewText ? View.VISIBLE : View.GONE);
163            if (preview.second) {
164                if (isRead) {
165                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.ITALIC);
166                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
167                } else {
168                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD_ITALIC);
169                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
170                }
171            } else {
172                if (isRead) {
173                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
174                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
175                } else {
176                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD);
177                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
178                }
179            }
180            if (status == Message.STATUS_RECEIVED) {
181                if (conversation.getMode() == Conversation.MODE_MULTI) {
182                    viewHolder.binding.senderName.setVisibility(View.VISIBLE);
183                    viewHolder.binding.senderName.setText(
184                            UIHelper.getMessageDisplayName(message).split("\\s+")[0] + ':');
185                } else {
186                    viewHolder.binding.senderName.setVisibility(View.GONE);
187                }
188            } else if (message.getType() != Message.TYPE_STATUS) {
189                viewHolder.binding.senderName.setVisibility(View.VISIBLE);
190                viewHolder.binding.senderName.setText(activity.getString(R.string.me) + ':');
191            } else {
192                viewHolder.binding.senderName.setVisibility(View.GONE);
193            }
194        }
195
196        final Optional<OngoingRtpSession> ongoingCall;
197        if (conversation.getMode() == Conversational.MODE_MULTI) {
198            ongoingCall = Optional.absent();
199        } else {
200            ongoingCall =
201                    activity.xmppConnectionService
202                            .getJingleConnectionManager()
203                            .getOngoingRtpConnection(conversation.getContact());
204        }
205
206        if (ongoingCall.isPresent()) {
207            viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
208            viewHolder.binding.notificationStatus.setImageResource(
209                    R.drawable.ic_phone_in_talk_24dp);
210        } else {
211            final long muted_till =
212                    conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
213            if (muted_till == Long.MAX_VALUE) {
214                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
215                viewHolder.binding.notificationStatus.setImageResource(
216                        R.drawable.ic_notifications_off_24dp);
217            } else if (muted_till >= System.currentTimeMillis()) {
218                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
219                viewHolder.binding.notificationStatus.setImageResource(
220                        R.drawable.ic_notifications_paused_24dp);
221            } else if (conversation.alwaysNotify()) {
222                viewHolder.binding.notificationStatus.setVisibility(View.GONE);
223            } else {
224                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
225                viewHolder.binding.notificationStatus.setImageResource(
226                        R.drawable.ic_notifications_none_24dp);
227            }
228        }
229
230        long timestamp;
231        if (draft != null) {
232            timestamp = draft.getTimestamp();
233        } else {
234            timestamp = conversation.getLatestMessage().getTimeSent();
235        }
236        viewHolder.binding.pinnedOnTop.setVisibility(
237                conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false)
238                        ? View.VISIBLE
239                        : View.GONE);
240        viewHolder.binding.conversationLastupdate.setText(
241                UIHelper.readableTimeDifference(activity, timestamp));
242        AvatarWorkerTask.loadAvatar(
243                conversation,
244                viewHolder.binding.conversationImage,
245                R.dimen.avatar_on_conversation_overview);
246        viewHolder.itemView.setOnClickListener(v -> listener.onConversationClick(v, conversation));
247    }
248
249    @Override
250    public int getItemCount() {
251        return conversations.size();
252    }
253
254    public void setConversationClickListener(OnConversationClickListener listener) {
255        this.listener = listener;
256    }
257
258    public void insert(Conversation c, int position) {
259        conversations.add(position, c);
260        notifyDataSetChanged();
261    }
262
263    public void remove(Conversation conversation, int position) {
264        conversations.remove(conversation);
265        notifyItemRemoved(position);
266    }
267
268    public interface OnConversationClickListener {
269        void onConversationClick(View view, Conversation conversation);
270    }
271
272    static class ConversationViewHolder extends RecyclerView.ViewHolder {
273        private final ItemConversationBinding binding;
274
275        private ConversationViewHolder(final ItemConversationBinding binding) {
276            super(binding.getRoot());
277            this.binding = binding;
278        }
279    }
280}