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