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