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}