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.DrawableRes;
 10import androidx.annotation.NonNull;
 11import androidx.databinding.DataBindingUtil;
 12import androidx.recyclerview.widget.RecyclerView;
 13
 14import com.google.android.material.color.MaterialColors;
 15import com.google.common.base.Optional;
 16
 17import eu.siacs.conversations.R;
 18import eu.siacs.conversations.databinding.ItemConversationBinding;
 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.Attachment;
 25import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 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
 31import java.util.List;
 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.item_conversation,
 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.setBackgroundResource(R.drawable.background_selected_item_conversation);
 72            //viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurfaceDim));
 73        } else {
 74            viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurface));
 75        }
 76
 77        final Message message = conversation.getLatestMessage();
 78        final int unreadCount = conversation.unreadCount();
 79        final boolean isRead = conversation.isRead();
 80        final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
 81        if (unreadCount > 0) {
 82            viewHolder.binding.unreadCount.setVisibility(View.VISIBLE);
 83            viewHolder.binding.unreadCount.setUnreadCount(unreadCount);
 84        } else {
 85            viewHolder.binding.unreadCount.setVisibility(View.GONE);
 86        }
 87
 88        if (isRead) {
 89            viewHolder.binding.conversationName.setTypeface(null, Typeface.NORMAL);
 90        } else {
 91            viewHolder.binding.conversationName.setTypeface(null, Typeface.BOLD);
 92        }
 93
 94        if (draft != null) {
 95            viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
 96            viewHolder.binding.conversationLastmsg.setText(draft.getMessage());
 97            viewHolder.binding.senderName.setText(R.string.draft);
 98            viewHolder.binding.senderName.setVisibility(View.VISIBLE);
 99            viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
100            viewHolder.binding.senderName.setTypeface(null, Typeface.ITALIC);
101        } else {
102            final boolean fileAvailable = !message.isDeleted();
103            final boolean showPreviewText;
104            if (fileAvailable
105                    && (message.isFileOrImage()
106                            || message.treatAsDownloadable()
107                            || message.isGeoUri())) {
108                final var attachment = Attachment.of(message);
109                final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
110                showPreviewText = false;
111                viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
112                viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
113            } else {
114                viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE);
115                showPreviewText = true;
116            }
117            final Pair<CharSequence, Boolean> preview =
118                    UIHelper.getMessagePreview(
119                            activity,
120                            message,
121                            viewHolder.binding.conversationLastmsg.getCurrentTextColor());
122            if (showPreviewText) {
123                viewHolder.binding.conversationLastmsg.setText(UIHelper.shorten(preview.first));
124            } else {
125                viewHolder.binding.conversationLastmsgImg.setContentDescription(preview.first);
126            }
127            viewHolder.binding.conversationLastmsg.setVisibility(
128                    showPreviewText ? View.VISIBLE : View.GONE);
129            if (preview.second) {
130                if (isRead) {
131                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.ITALIC);
132                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
133                } else {
134                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD_ITALIC);
135                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
136                }
137            } else {
138                if (isRead) {
139                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.NORMAL);
140                    viewHolder.binding.senderName.setTypeface(null, Typeface.NORMAL);
141                } else {
142                    viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.BOLD);
143                    viewHolder.binding.senderName.setTypeface(null, Typeface.BOLD);
144                }
145            }
146            if (message.getStatus() == Message.STATUS_RECEIVED) {
147                if (conversation.getMode() == Conversation.MODE_MULTI) {
148                    viewHolder.binding.senderName.setVisibility(View.VISIBLE);
149                    viewHolder.binding.senderName.setText(
150                            UIHelper.getMessageDisplayName(message).split("\\s+")[0] + ':');
151                } else {
152                    viewHolder.binding.senderName.setVisibility(View.GONE);
153                }
154            } else if (message.getType() != Message.TYPE_STATUS) {
155                viewHolder.binding.senderName.setVisibility(View.VISIBLE);
156                viewHolder.binding.senderName.setText(activity.getString(R.string.me) + ':');
157            } else {
158                viewHolder.binding.senderName.setVisibility(View.GONE);
159            }
160        }
161
162        final Optional<OngoingRtpSession> ongoingCall;
163        if (conversation.getMode() == Conversational.MODE_MULTI) {
164            ongoingCall = Optional.absent();
165        } else {
166            ongoingCall =
167                    activity.xmppConnectionService
168                            .getJingleConnectionManager()
169                            .getOngoingRtpConnection(conversation.getContact());
170        }
171
172        if (ongoingCall.isPresent()) {
173            viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
174            viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_phone_in_talk_24dp);
175        } else {
176            final long muted_till =
177                    conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
178            if (muted_till == Long.MAX_VALUE) {
179                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
180                viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_off_24dp);
181            } else if (muted_till >= System.currentTimeMillis()) {
182                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
183                viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_paused_24dp);
184            } else if (conversation.alwaysNotify()) {
185                viewHolder.binding.notificationStatus.setVisibility(View.GONE);
186            } else {
187                viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
188                viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_none_24dp);
189            }
190        }
191
192        long timestamp;
193        if (draft != null) {
194            timestamp = draft.getTimestamp();
195        } else {
196            timestamp = conversation.getLatestMessage().getTimeSent();
197        }
198        viewHolder.binding.pinnedOnTop.setVisibility(
199                conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false)
200                        ? View.VISIBLE
201                        : View.GONE);
202        viewHolder.binding.conversationLastupdate.setText(
203                UIHelper.readableTimeDifference(activity, timestamp));
204        AvatarWorkerTask.loadAvatar(
205                conversation,
206                viewHolder.binding.conversationImage,
207                R.dimen.avatar_on_conversation_overview);
208        viewHolder.itemView.setOnClickListener(v -> listener.onConversationClick(v, conversation));
209    }
210
211    @Override
212    public int getItemCount() {
213        return conversations.size();
214    }
215
216    public void setConversationClickListener(OnConversationClickListener listener) {
217        this.listener = listener;
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 ItemConversationBinding binding;
236
237        private ConversationViewHolder(final ItemConversationBinding binding) {
238            super(binding.getRoot());
239            this.binding = binding;
240        }
241    }
242}