1package eu.siacs.conversations.ui.adapter;
2
3import android.app.PendingIntent;
4import android.content.IntentSender;
5import android.view.ContextMenu;
6import android.view.LayoutInflater;
7import android.view.View;
8import android.view.ViewGroup;
9import android.widget.Toast;
10import androidx.annotation.NonNull;
11import androidx.databinding.DataBindingUtil;
12import androidx.recyclerview.widget.DiffUtil;
13import androidx.recyclerview.widget.ListAdapter;
14import androidx.recyclerview.widget.RecyclerView;
15import com.google.common.base.Strings;
16import eu.siacs.conversations.R;
17import eu.siacs.conversations.crypto.PgpEngine;
18import eu.siacs.conversations.databinding.ItemContactBinding;
19import eu.siacs.conversations.entities.Contact;
20import eu.siacs.conversations.entities.MucOptions;
21import eu.siacs.conversations.services.XmppConnectionService;
22import eu.siacs.conversations.ui.ConferenceDetailsActivity;
23import eu.siacs.conversations.ui.XmppActivity;
24import eu.siacs.conversations.ui.util.AvatarWorkerTask;
25import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper;
26import eu.siacs.conversations.utils.Compatibility;
27import eu.siacs.conversations.xmpp.Jid;
28import im.conversations.android.xmpp.model.muc.Role;
29import org.openintents.openpgp.util.OpenPgpUtils;
30
31public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHolder>
32 implements View.OnCreateContextMenuListener {
33
34 static final DiffUtil.ItemCallback<MucOptions.User> DIFF =
35 new DiffUtil.ItemCallback<MucOptions.User>() {
36 @Override
37 public boolean areItemsTheSame(
38 @NonNull MucOptions.User a, @NonNull MucOptions.User b) {
39 final Jid fullA = a.getFullJid();
40 final Jid fullB = b.getFullJid();
41 final Jid realA = a.getRealJid();
42 final Jid realB = b.getRealJid();
43 if (fullA != null && fullB != null) {
44 return fullA.equals(fullB);
45 } else if (realA != null && realB != null) {
46 return realA.equals(realB);
47 } else {
48 return false;
49 }
50 }
51
52 @Override
53 public boolean areContentsTheSame(
54 @NonNull MucOptions.User a, @NonNull MucOptions.User b) {
55 return a.equals(b);
56 }
57 };
58 private final boolean advancedMode;
59 private MucOptions.User selectedUser = null;
60
61 public UserAdapter(final boolean advancedMode) {
62 super(DIFF);
63 this.advancedMode = advancedMode;
64 }
65
66 @NonNull
67 @Override
68 public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
69 return new ViewHolder(
70 DataBindingUtil.inflate(
71 LayoutInflater.from(viewGroup.getContext()),
72 R.layout.item_contact,
73 viewGroup,
74 false));
75 }
76
77 @Override
78 public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
79 final MucOptions.User user = getItem(position);
80 AvatarWorkerTask.loadAvatar(user, viewHolder.binding.contactPhoto, R.dimen.avatar);
81 viewHolder
82 .binding
83 .getRoot()
84 .setOnClickListener(
85 v -> {
86 final XmppActivity activity = XmppActivity.find(v);
87 if (activity == null) {
88 return;
89 }
90 final var contact = user.getContact();
91 if (user.getRole() == Role.NONE && contact != null) {
92 Toast.makeText(
93 activity,
94 activity.getString(
95 R.string.user_has_left_conference,
96 contact.getDisplayName()),
97 Toast.LENGTH_SHORT)
98 .show();
99 }
100 activity.highlightInMuc(user.getConversation(), user.getName());
101 });
102 viewHolder.binding.getRoot().setTag(user);
103 viewHolder.binding.getRoot().setOnCreateContextMenuListener(this);
104 viewHolder
105 .binding
106 .getRoot()
107 .setOnLongClickListener(
108 v -> {
109 selectedUser = user;
110 return false;
111 });
112 final String name = user.getName();
113 final Contact contact = user.getContact();
114 if (contact != null) {
115 final String displayName = contact.getDisplayName();
116 viewHolder.binding.contactDisplayName.setText(displayName);
117 if (name != null && !name.equals(displayName)) {
118 viewHolder.binding.contactJid.setText(
119 String.format(
120 "%s \u2022 %s",
121 name,
122 ConferenceDetailsActivity.getStatus(
123 viewHolder.binding.getRoot().getContext(),
124 user,
125 advancedMode)));
126 } else {
127 viewHolder.binding.contactJid.setText(
128 ConferenceDetailsActivity.getStatus(
129 viewHolder.binding.getRoot().getContext(), user, advancedMode));
130 }
131 } else {
132 viewHolder.binding.contactDisplayName.setText(Strings.nullToEmpty(name));
133 viewHolder.binding.contactJid.setText(
134 ConferenceDetailsActivity.getStatus(
135 viewHolder.binding.getRoot().getContext(), user, advancedMode));
136 }
137 if (advancedMode && user.getPgpKeyId() != 0) {
138 viewHolder.binding.key.setVisibility(View.VISIBLE);
139 viewHolder.binding.key.setOnClickListener(
140 v -> {
141 final XmppActivity activity = XmppActivity.find(v);
142 final XmppConnectionService service =
143 activity == null ? null : activity.xmppConnectionService;
144 final PgpEngine pgpEngine = service == null ? null : service.getPgpEngine();
145 if (pgpEngine != null) {
146 PendingIntent intent = pgpEngine.getIntentForKey(user.getPgpKeyId());
147 if (intent != null) {
148 try {
149 activity.startIntentSenderForResult(
150 intent.getIntentSender(),
151 0,
152 null,
153 0,
154 0,
155 0,
156 Compatibility.pgpStartIntentSenderOptions());
157 } catch (IntentSender.SendIntentException ignored) {
158
159 }
160 }
161 }
162 });
163 viewHolder.binding.key.setText(OpenPgpUtils.convertKeyIdToHex(user.getPgpKeyId()));
164 } else {
165 viewHolder.binding.key.setVisibility(View.GONE);
166 }
167 }
168
169 public MucOptions.User getSelectedUser() {
170 return selectedUser;
171 }
172
173 @Override
174 public void onCreateContextMenu(
175 ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
176 MucDetailsContextMenuHelper.onCreateContextMenu(menu, v);
177 }
178
179 static class ViewHolder extends RecyclerView.ViewHolder {
180
181 private final ItemContactBinding binding;
182
183 private ViewHolder(ItemContactBinding binding) {
184 super(binding.getRoot());
185 this.binding = binding;
186 }
187 }
188}