MucDetailsContextMenuHelper.java

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