1package eu.siacs.conversations.ui.util;
2
3import android.app.Activity;
4import android.preference.PreferenceManager;
5import android.text.SpannableString;
6import android.text.Spanned;
7import android.text.style.TypefaceSpan;
8import android.view.ContextMenu;
9import android.view.Menu;
10import android.view.MenuItem;
11import android.view.View;
12import com.google.android.material.dialog.MaterialAlertDialogBuilder;
13import eu.siacs.conversations.Config;
14import eu.siacs.conversations.R;
15import eu.siacs.conversations.entities.Account;
16import eu.siacs.conversations.entities.Contact;
17import eu.siacs.conversations.entities.Conversation;
18import eu.siacs.conversations.entities.MucOptions;
19import eu.siacs.conversations.entities.MucOptions.User;
20import eu.siacs.conversations.services.XmppConnectionService;
21import eu.siacs.conversations.ui.ConferenceDetailsActivity;
22import eu.siacs.conversations.ui.ConversationFragment;
23import eu.siacs.conversations.ui.ConversationsActivity;
24import eu.siacs.conversations.ui.MucUsersActivity;
25import eu.siacs.conversations.ui.XmppActivity;
26import eu.siacs.conversations.xmpp.Jid;
27import im.conversations.android.xmpp.model.muc.Affiliation;
28import im.conversations.android.xmpp.model.muc.Role;
29
30public final class MucDetailsContextMenuHelper {
31
32 public static void onCreateContextMenu(ContextMenu menu, View v) {
33 final XmppActivity activity = XmppActivity.find(v);
34 final Object tag = v.getTag();
35 if (tag instanceof User user && activity != null) {
36 activity.getMenuInflater().inflate(R.menu.muc_details_context, menu);
37 String name;
38 final Contact contact = user.getContact();
39 if (contact != null && contact.showInContactList()) {
40 name = contact.getDisplayName();
41 } else if (user.getRealJid() != null) {
42 name = user.getRealJid().asBareJid().toString();
43 } else {
44 name = user.getName();
45 }
46 menu.setHeaderTitle(name);
47 MucDetailsContextMenuHelper.configureMucDetailsContextMenu(
48 activity, menu, user.getConversation(), user);
49 }
50 }
51
52 public static void configureMucDetailsContextMenu(
53 Activity activity, Menu menu, Conversation conversation, User user) {
54 final MucOptions mucOptions = conversation.getMucOptions();
55 final boolean advancedMode =
56 PreferenceManager.getDefaultSharedPreferences(activity)
57 .getBoolean("advanced_muc_mode", false);
58 final boolean isGroupChat = mucOptions.isPrivateAndNonAnonymous();
59 MenuItem sendPrivateMessage = menu.findItem(R.id.send_private_message);
60 if (user != null && user.getRealJid() != null) {
61 MenuItem showContactDetails = menu.findItem(R.id.action_contact_details);
62 MenuItem startConversation = menu.findItem(R.id.start_conversation);
63 MenuItem giveMembership = menu.findItem(R.id.give_membership);
64 MenuItem removeMembership = menu.findItem(R.id.remove_membership);
65 MenuItem giveAdminPrivileges = menu.findItem(R.id.give_admin_privileges);
66 MenuItem giveOwnerPrivileges = menu.findItem(R.id.give_owner_privileges);
67 MenuItem removeOwnerPrivileges = menu.findItem(R.id.revoke_owner_privileges);
68 MenuItem removeAdminPrivileges = menu.findItem(R.id.remove_admin_privileges);
69 MenuItem removeFromRoom = menu.findItem(R.id.remove_from_room);
70 MenuItem managePermissions = menu.findItem(R.id.manage_permissions);
71 removeFromRoom.setTitle(
72 isGroupChat ? R.string.remove_from_room : R.string.remove_from_channel);
73 MenuItem banFromConference = menu.findItem(R.id.ban_from_conference);
74 banFromConference.setTitle(
75 isGroupChat ? R.string.ban_from_conference : R.string.ban_from_channel);
76 MenuItem invite = menu.findItem(R.id.invite);
77 startConversation.setVisible(true);
78 final Contact contact = user.getContact();
79 final User self = conversation.getMucOptions().getSelf();
80 if ((contact != null && contact.showInRoster())
81 || mucOptions.isPrivateAndNonAnonymous()) {
82 showContactDetails.setVisible(contact == null || !contact.isSelf());
83 }
84 if ((activity instanceof ConferenceDetailsActivity
85 || activity instanceof MucUsersActivity)
86 && user.getRole() == Role.NONE) {
87 invite.setVisible(true);
88 }
89 boolean managePermissionsVisible = false;
90 if ((self.ranks(Affiliation.ADMIN) && self.outranks(user.getAffiliation()))
91 || self.getAffiliation() == Affiliation.OWNER) {
92 if (advancedMode) {
93 if (!user.ranks(Affiliation.MEMBER)) {
94 managePermissionsVisible = true;
95 giveMembership.setVisible(true);
96 } else if (user.getAffiliation() == Affiliation.MEMBER) {
97 managePermissionsVisible = true;
98 removeMembership.setVisible(true);
99 }
100 if (!Config.DISABLE_BAN) {
101 managePermissionsVisible = true;
102 banFromConference.setVisible(true);
103 }
104 } else {
105 if (!Config.DISABLE_BAN || conversation.getMucOptions().membersOnly()) {
106 removeFromRoom.setVisible(true);
107 }
108 }
109 }
110 if (self.ranks(Affiliation.OWNER)) {
111 if (isGroupChat || advancedMode || user.getAffiliation() == Affiliation.OWNER) {
112 if (!user.ranks(Affiliation.OWNER)) {
113 managePermissionsVisible = true;
114 giveOwnerPrivileges.setVisible(true);
115 } else if (user.getAffiliation() == Affiliation.OWNER) {
116 managePermissionsVisible = true;
117 removeOwnerPrivileges.setVisible(true);
118 }
119 }
120 if (!isGroupChat || advancedMode || user.getAffiliation() == Affiliation.ADMIN) {
121 if (!user.ranks(Affiliation.ADMIN)) {
122 managePermissionsVisible = true;
123 giveAdminPrivileges.setVisible(true);
124 } else if (user.getAffiliation() == Affiliation.ADMIN) {
125 managePermissionsVisible = true;
126 removeAdminPrivileges.setVisible(true);
127 }
128 }
129 }
130 managePermissions.setVisible(managePermissionsVisible);
131 sendPrivateMessage.setVisible(
132 !isGroupChat && mucOptions.allowPm() && user.ranks(Role.VISITOR));
133 } else {
134 sendPrivateMessage.setVisible(true);
135 sendPrivateMessage.setEnabled(
136 user != null && mucOptions.allowPm() && user.ranks(Role.VISITOR));
137 }
138 }
139
140 public static boolean onContextItemSelected(MenuItem item, User user, XmppActivity activity) {
141 return onContextItemSelected(item, user, activity, null);
142 }
143
144 public static boolean onContextItemSelected(
145 MenuItem item, User user, XmppActivity activity, final String fingerprint) {
146 final Conversation conversation = user.getConversation();
147 final XmppConnectionService.OnAffiliationChanged onAffiliationChanged =
148 activity instanceof XmppConnectionService.OnAffiliationChanged
149 ? (XmppConnectionService.OnAffiliationChanged) activity
150 : null;
151 Jid jid = user.getRealJid();
152 switch (item.getItemId()) {
153 case R.id.action_contact_details:
154 final Jid realJid = user.getRealJid();
155 final Account account = conversation.getAccount();
156 final Contact contact =
157 realJid == null ? null : account.getRoster().getContact(realJid);
158 if (contact != null) {
159 activity.switchToContactDetails(contact, fingerprint);
160 }
161 return true;
162 case R.id.start_conversation:
163 startConversation(user, activity);
164 return true;
165 case R.id.give_admin_privileges:
166 activity.xmppConnectionService.changeAffiliationInConference(
167 conversation, jid, Affiliation.ADMIN, onAffiliationChanged);
168 return true;
169 case R.id.give_membership:
170 case R.id.remove_admin_privileges:
171 case R.id.revoke_owner_privileges:
172 activity.xmppConnectionService.changeAffiliationInConference(
173 conversation, jid, Affiliation.MEMBER, onAffiliationChanged);
174 return true;
175 case R.id.give_owner_privileges:
176 activity.xmppConnectionService.changeAffiliationInConference(
177 conversation, jid, Affiliation.OWNER, onAffiliationChanged);
178 return true;
179 case R.id.remove_membership:
180 activity.xmppConnectionService.changeAffiliationInConference(
181 conversation, jid, Affiliation.NONE, onAffiliationChanged);
182 return true;
183 case R.id.remove_from_room:
184 removeFromRoom(user, activity, onAffiliationChanged);
185 return true;
186 case R.id.ban_from_conference:
187 activity.xmppConnectionService.changeAffiliationInConference(
188 conversation, jid, Affiliation.OUTCAST, onAffiliationChanged);
189 if (user.getRole() != Role.NONE) {
190 activity.xmppConnectionService.changeRoleInConference(
191 conversation, user.getName(), Role.NONE);
192 }
193 return true;
194 case R.id.send_private_message:
195 if (activity instanceof ConversationsActivity) {
196 ConversationFragment conversationFragment = ConversationFragment.get(activity);
197 if (conversationFragment != null) {
198 conversationFragment.privateMessageWith(user.getFullJid());
199 return true;
200 }
201 }
202 activity.privateMsgInMuc(conversation, user.getName());
203 return true;
204 case R.id.invite:
205 // TODO use direct invites for public conferences
206 if (user.ranks(Affiliation.MEMBER)) {
207 activity.xmppConnectionService.directInvite(conversation, jid.asBareJid());
208 } else {
209 activity.xmppConnectionService.invite(conversation, jid);
210 }
211 return true;
212 default:
213 return false;
214 }
215 }
216
217 private static void removeFromRoom(
218 final User user,
219 XmppActivity activity,
220 XmppConnectionService.OnAffiliationChanged onAffiliationChanged) {
221 final Conversation conversation = user.getConversation();
222 if (conversation.getMucOptions().membersOnly()) {
223 activity.xmppConnectionService.changeAffiliationInConference(
224 conversation, user.getRealJid(), Affiliation.NONE, onAffiliationChanged);
225 if (user.getRole() != Role.NONE) {
226 activity.xmppConnectionService.changeRoleInConference(
227 conversation, user.getName(), Role.NONE);
228 }
229 } else {
230 final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
231 builder.setTitle(R.string.ban_from_conference);
232 String jid = user.getRealJid().asBareJid().toString();
233 SpannableString message =
234 new SpannableString(
235 activity.getString(R.string.removing_from_public_conference, jid));
236 int start = message.toString().indexOf(jid);
237 if (start >= 0) {
238 message.setSpan(
239 new TypefaceSpan("monospace"),
240 start,
241 start + jid.length(),
242 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
243 }
244 builder.setMessage(message);
245 builder.setNegativeButton(R.string.cancel, null);
246 builder.setPositiveButton(
247 R.string.ban_now,
248 (dialog, which) -> {
249 activity.xmppConnectionService.changeAffiliationInConference(
250 conversation,
251 user.getRealJid(),
252 Affiliation.OUTCAST,
253 onAffiliationChanged);
254 if (user.getRole() != Role.NONE) {
255 activity.xmppConnectionService.changeRoleInConference(
256 conversation, user.getName(), Role.NONE);
257 }
258 });
259 builder.create().show();
260 }
261 }
262
263 private static void startConversation(User user, XmppActivity activity) {
264 if (user.getRealJid() != null) {
265 Conversation newConversation =
266 activity.xmppConnectionService.findOrCreateConversation(
267 user.getAccount(), user.getRealJid().asBareJid(), false, true);
268 activity.switchToConversation(newConversation);
269 }
270 }
271}