1package eu.siacs.conversations.ui;
2
3import android.app.PendingIntent;
4import android.content.Context;
5import android.content.Intent;
6import android.os.Bundle;
7import android.text.Editable;
8import android.text.SpannableStringBuilder;
9import android.text.TextWatcher;
10import android.view.Menu;
11import android.view.MenuItem;
12import android.view.View;
13import android.view.View.OnClickListener;
14import android.widget.Toast;
15
16import androidx.appcompat.app.AlertDialog;
17import androidx.databinding.DataBindingUtil;
18
19import java.util.Collections;
20import java.util.List;
21import java.util.concurrent.atomic.AtomicInteger;
22
23import eu.siacs.conversations.Config;
24import eu.siacs.conversations.R;
25import eu.siacs.conversations.databinding.ActivityMucDetailsBinding;
26import eu.siacs.conversations.entities.Account;
27import eu.siacs.conversations.entities.Bookmark;
28import eu.siacs.conversations.entities.Conversation;
29import eu.siacs.conversations.entities.MucOptions;
30import eu.siacs.conversations.entities.MucOptions.User;
31import eu.siacs.conversations.services.XmppConnectionService;
32import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
33import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate;
34import eu.siacs.conversations.ui.adapter.MediaAdapter;
35import eu.siacs.conversations.ui.adapter.UserPreviewAdapter;
36import eu.siacs.conversations.ui.interfaces.OnMediaLoaded;
37import eu.siacs.conversations.ui.util.Attachment;
38import eu.siacs.conversations.ui.util.AvatarWorkerTask;
39import eu.siacs.conversations.ui.util.GridManager;
40import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
41import eu.siacs.conversations.ui.util.MucConfiguration;
42import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper;
43import eu.siacs.conversations.ui.util.MyLinkify;
44import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
45import eu.siacs.conversations.utils.AccountUtils;
46import eu.siacs.conversations.utils.Compatibility;
47import eu.siacs.conversations.utils.EmojiWrapper;
48import eu.siacs.conversations.utils.StringUtils;
49import eu.siacs.conversations.utils.StylingHelper;
50import eu.siacs.conversations.utils.XmppUri;
51import eu.siacs.conversations.xmpp.Jid;
52import me.drakeet.support.toast.ToastCompat;
53
54import static eu.siacs.conversations.entities.Bookmark.printableValue;
55import static eu.siacs.conversations.utils.StringUtils.changed;
56
57public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnConfigurationPushed, XmppConnectionService.OnRoomDestroy, TextWatcher, OnMediaLoaded {
58 public static final String ACTION_VIEW_MUC = "view_muc";
59
60 private Conversation mConversation;
61 private ActivityMucDetailsBinding binding;
62 private MediaAdapter mMediaAdapter;
63 private UserPreviewAdapter mUserPreviewAdapter;
64 private String uuid = null;
65
66 private boolean mAdvancedMode = false;
67
68 private final UiCallback<Conversation> renameCallback = new UiCallback<Conversation>() {
69 @Override
70 public void success(Conversation object) {
71 displayToast(getString(R.string.your_nick_has_been_changed));
72 runOnUiThread(() -> {
73 updateView();
74 });
75
76 }
77
78 @Override
79 public void error(final int errorCode, Conversation object) {
80 displayToast(getString(errorCode));
81 }
82
83 @Override
84 public void userInputRequired(PendingIntent pi, Conversation object) {
85
86 }
87 };
88
89 private final OnClickListener mNotifyStatusClickListener = new OnClickListener() {
90 @Override
91 public void onClick(View v) {
92 AlertDialog.Builder builder = new AlertDialog.Builder(ConferenceDetailsActivity.this);
93 builder.setTitle(R.string.pref_notification_settings);
94 String[] choices = {
95 getString(R.string.notify_on_all_messages),
96 getString(R.string.notify_only_when_highlighted),
97 getString(R.string.notify_never)
98 };
99 final AtomicInteger choice;
100 if (mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0) == Long.MAX_VALUE) {
101 choice = new AtomicInteger(2);
102 } else {
103 choice = new AtomicInteger(mConversation.alwaysNotify() ? 0 : 1);
104 }
105 builder.setSingleChoiceItems(choices, choice.get(), (dialog, which) -> choice.set(which));
106 builder.setNegativeButton(R.string.cancel, null);
107 builder.setPositiveButton(R.string.ok, (dialog, which) -> {
108 if (choice.get() == 2) {
109 mConversation.setMutedTill(Long.MAX_VALUE);
110 } else {
111 mConversation.setMutedTill(0);
112 mConversation.setAttribute(Conversation.ATTRIBUTE_ALWAYS_NOTIFY, String.valueOf(choice.get() == 0));
113 }
114 xmppConnectionService.updateConversation(mConversation);
115 updateView();
116 });
117 builder.create().show();
118 }
119 };
120
121 private final OnClickListener mChangeConferenceSettings = new OnClickListener() {
122 @Override
123 public void onClick(View v) {
124 final MucOptions mucOptions = mConversation.getMucOptions();
125 AlertDialog.Builder builder = new AlertDialog.Builder(ConferenceDetailsActivity.this);
126 MucConfiguration configuration = MucConfiguration.get(ConferenceDetailsActivity.this, mAdvancedMode, mucOptions);
127 builder.setTitle(configuration.title);
128 final boolean[] values = configuration.values;
129 builder.setMultiChoiceItems(configuration.names, values, (dialog, which, isChecked) -> values[which] = isChecked);
130 builder.setNegativeButton(R.string.cancel, null);
131 builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
132 Bundle options = configuration.toBundle(values);
133 options.putString("muc#roomconfig_persistentroom", "1");
134 xmppConnectionService.pushConferenceConfiguration(mConversation,
135 options,
136 ConferenceDetailsActivity.this);
137 });
138 builder.create().show();
139 }
140 };
141
142
143 @Override
144 public void onConversationUpdate() {
145 refreshUi();
146 }
147
148 @Override
149 public void onMucRosterUpdate() {
150 refreshUi();
151 }
152
153 @Override
154 protected void refreshUiReal() {
155 updateView();
156 }
157
158 @Override
159 protected void onCreate(Bundle savedInstanceState) {
160 super.onCreate(savedInstanceState);
161 this.binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_details);
162 this.binding.changeConferenceButton.setOnClickListener(this.mChangeConferenceSettings);
163 setSupportActionBar(binding.toolbar);
164 configureActionBar(getSupportActionBar());
165 this.binding.editNickButton.setOnClickListener(v -> quickEdit(mConversation.getMucOptions().getActualNick(),
166 R.string.nickname,
167 value -> {
168 if (xmppConnectionService.renameInMuc(mConversation, value, renameCallback)) {
169 return null;
170 } else {
171 return getString(R.string.invalid_muc_nick);
172 }
173 }));
174 this.mAdvancedMode = getPreferences().getBoolean("advanced_muc_mode", false);
175 this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
176 this.binding.notificationStatusButton.setOnClickListener(this.mNotifyStatusClickListener);
177 this.binding.yourPhoto.setOnClickListener(v -> {
178 final MucOptions mucOptions = mConversation.getMucOptions();
179 if (!mucOptions.hasVCards()) {
180 Toast.makeText(this, R.string.host_does_not_support_group_chat_avatars, Toast.LENGTH_SHORT).show();
181 return;
182 }
183 if (!mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER)) {
184 Toast.makeText(this, R.string.only_the_owner_can_change_group_chat_avatar, Toast.LENGTH_SHORT).show();
185 return;
186 }
187 final Intent intent = new Intent(this, PublishGroupChatProfilePictureActivity.class);
188 intent.putExtra("uuid", mConversation.getUuid());
189 startActivity(intent);
190 });
191 this.binding.editMucNameButton.setOnClickListener(this::onMucEditButtonClicked);
192 this.binding.mucEditTitle.addTextChangedListener(this);
193 this.binding.mucEditSubject.addTextChangedListener(this);
194 this.binding.mucEditSubject.addTextChangedListener(new StylingHelper.MessageEditorStyler(this.binding.mucEditSubject));
195 this.mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);
196 this.mUserPreviewAdapter = new UserPreviewAdapter();
197 this.binding.media.setAdapter(mMediaAdapter);
198 this.binding.users.setAdapter(mUserPreviewAdapter);
199 GridManager.setupLayoutManager(this, this.binding.media, R.dimen.media_size);
200 GridManager.setupLayoutManager(this, this.binding.users, R.dimen.media_size);
201 this.binding.invite.setOnClickListener(v -> inviteToConversation(mConversation));
202 this.binding.showUsers.setOnClickListener(v -> {
203 Intent intent = new Intent(this, MucUsersActivity.class);
204 intent.putExtra("uuid", mConversation.getUuid());
205 startActivity(intent);
206 });
207 }
208
209 @Override
210 protected void onStart() {
211 super.onStart();
212 final int theme = findTheme();
213 if (this.mTheme != theme) {
214 recreate();
215 }
216 binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE);
217 }
218
219 @Override
220 public boolean onOptionsItemSelected(MenuItem menuItem) {
221 if (MenuDoubleTabUtil.shouldIgnoreTap()) {
222 return false;
223 }
224 switch (menuItem.getItemId()) {
225 case android.R.id.home:
226 finish();
227 break;
228 case R.id.action_share_http:
229 shareLink(true);
230 break;
231 case R.id.action_share_uri:
232 shareLink(false);
233 break;
234 case R.id.action_save_as_bookmark:
235 saveAsBookmark();
236 break;
237 case R.id.action_delete_bookmark:
238 deleteBookmark();
239 break;
240 case R.id.action_destroy_room:
241 destroyRoom();
242 break;
243 case R.id.action_advanced_mode:
244 this.mAdvancedMode = !menuItem.isChecked();
245 menuItem.setChecked(this.mAdvancedMode);
246 getPreferences().edit().putBoolean("advanced_muc_mode", mAdvancedMode).apply();
247 final boolean online = mConversation != null && mConversation.getMucOptions().online();
248 this.binding.mucInfoMore.setVisibility(this.mAdvancedMode && online ? View.VISIBLE : View.GONE);
249 invalidateOptionsMenu();
250 updateView();
251 break;
252 }
253 return super.onOptionsItemSelected(menuItem);
254 }
255
256 @Override
257 public boolean onContextItemSelected(MenuItem item) {
258 final User user = mUserPreviewAdapter.getSelectedUser();
259 if (user == null) {
260 Toast.makeText(this, R.string.unable_to_perform_this_action, Toast.LENGTH_SHORT).show();
261 return true;
262 }
263 if (!MucDetailsContextMenuHelper.onContextItemSelected(item, mUserPreviewAdapter.getSelectedUser(), this)) {
264 return super.onContextItemSelected(item);
265 }
266 return true;
267 }
268
269 public void onMucEditButtonClicked(View v) {
270 if (this.binding.mucEditor.getVisibility() == View.GONE) {
271 final MucOptions mucOptions = mConversation.getMucOptions();
272 this.binding.mucEditor.setVisibility(View.VISIBLE);
273 this.binding.mucDisplay.setVisibility(View.GONE);
274 this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp));
275 final String name = mucOptions.getName();
276 this.binding.mucEditTitle.setText("");
277 final boolean owner = mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER);
278 if (owner || printableValue(name)) {
279 this.binding.mucEditTitle.setVisibility(View.VISIBLE);
280 if (name != null) {
281 this.binding.mucEditTitle.append(name);
282 }
283 } else {
284 this.binding.mucEditTitle.setVisibility(View.GONE);
285 }
286 this.binding.mucEditTitle.setEnabled(owner);
287 final String subject = mucOptions.getSubject();
288 this.binding.mucEditSubject.setText("");
289 if (subject != null) {
290 this.binding.mucEditSubject.append(subject);
291 }
292 this.binding.mucEditSubject.setEnabled(mucOptions.canChangeSubject());
293 if (!owner) {
294 this.binding.mucEditSubject.requestFocus();
295 }
296 } else {
297 String subject = this.binding.mucEditSubject.isEnabled() ? this.binding.mucEditSubject.getEditableText().toString().trim() : null;
298 String name = this.binding.mucEditTitle.isEnabled() ? this.binding.mucEditTitle.getEditableText().toString().trim() : null;
299 onMucInfoUpdated(subject, name);
300 SoftKeyboardUtils.hideSoftKeyboard(this);
301 hideEditor();
302 }
303 }
304
305 private void hideEditor() {
306 this.binding.mucEditor.setVisibility(View.GONE);
307 this.binding.mucDisplay.setVisibility(View.VISIBLE);
308 this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_edit_body, R.drawable.ic_edit_black_24dp));
309 }
310
311 private void onMucInfoUpdated(String subject, String name) {
312 final MucOptions mucOptions = mConversation.getMucOptions();
313 if (mucOptions.canChangeSubject() && changed(mucOptions.getSubject(), subject)) {
314 xmppConnectionService.pushSubjectToConference(mConversation, subject);
315 }
316 if (mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER) && changed(mucOptions.getName(), name)) {
317 Bundle options = new Bundle();
318 options.putString("muc#roomconfig_persistentroom", "1");
319 options.putString("muc#roomconfig_roomname", StringUtils.nullOnEmpty(name));
320 xmppConnectionService.pushConferenceConfiguration(mConversation, options, this);
321 }
322 }
323
324
325 @Override
326 protected String getShareableUri(boolean http) {
327 if (mConversation != null) {
328 if (http) {
329 return "https://conversations.im/j/" + XmppUri.lameUrlEncode(mConversation.getJid().asBareJid().toEscapedString());
330 } else {
331 return "xmpp:" + mConversation.getJid().asBareJid() + "?join";
332 }
333 } else {
334 return null;
335 }
336 }
337
338 @Override
339 public boolean onPrepareOptionsMenu(Menu menu) {
340 MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
341 MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
342 MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode);
343 MenuItem menuItemDestroyRoom = menu.findItem(R.id.action_destroy_room);
344 menuItemAdvancedMode.setChecked(mAdvancedMode);
345 if (mConversation == null) {
346 return true;
347 }
348 if (mConversation.getBookmark() != null) {
349 menuItemSaveBookmark.setVisible(false);
350 menuItemDeleteBookmark.setVisible(true);
351 } else {
352 menuItemDeleteBookmark.setVisible(false);
353 menuItemSaveBookmark.setVisible(true);
354 }
355 menuItemDestroyRoom.setVisible(mConversation.getMucOptions().getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER));
356 return true;
357 }
358
359 @Override
360 public boolean onCreateOptionsMenu(Menu menu) {
361 final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous();
362 getMenuInflater().inflate(R.menu.muc_details, menu);
363 final MenuItem share = menu.findItem(R.id.action_share);
364 share.setVisible(!groupChat);
365 final MenuItem destroy = menu.findItem(R.id.action_destroy_room);
366 destroy.setTitle(groupChat ? R.string.destroy_room : R.string.destroy_channel);
367 AccountUtils.showHideMenuItems(menu);
368 return super.onCreateOptionsMenu(menu);
369 }
370
371 @Override
372 public void onMediaLoaded(List<Attachment> attachments) {
373 runOnUiThread(() -> {
374 int limit = GridManager.getCurrentColumnCount(binding.media);
375 mMediaAdapter.setAttachments(attachments.subList(0, Math.min(limit, attachments.size())));
376 binding.mediaWrapper.setVisibility(attachments.size() > 0 ? View.VISIBLE : View.GONE);
377 });
378
379 }
380
381
382 protected void saveAsBookmark() {
383 xmppConnectionService.saveConversationAsBookmark(mConversation, mConversation.getMucOptions().getName());
384 }
385
386 protected void deleteBookmark() {
387 final Account account = mConversation.getAccount();
388 final Bookmark bookmark = mConversation.getBookmark();
389 bookmark.setConversation(null);
390 xmppConnectionService.deleteBookmark(account, bookmark);
391 updateView();
392 }
393
394 protected void destroyRoom() {
395 final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous();
396 AlertDialog.Builder builder = new AlertDialog.Builder(this);
397 builder.setTitle(groupChat ? R.string.destroy_room : R.string.destroy_channel);
398 builder.setMessage(groupChat ? R.string.destroy_room_dialog : R.string.destroy_channel_dialog);
399 builder.setPositiveButton(R.string.ok, (dialog, which) -> {
400 xmppConnectionService.destroyRoom(mConversation, ConferenceDetailsActivity.this);
401 });
402 builder.setNegativeButton(R.string.cancel, null);
403 final AlertDialog dialog = builder.create();
404 dialog.setCanceledOnTouchOutside(false);
405 dialog.show();
406 }
407
408 @Override
409 void onBackendConnected() {
410 if (mPendingConferenceInvite != null) {
411 mPendingConferenceInvite.execute(this);
412 mPendingConferenceInvite = null;
413 }
414 if (getIntent().getAction().equals(ACTION_VIEW_MUC)) {
415 this.uuid = getIntent().getExtras().getString("uuid");
416 }
417 if (uuid != null) {
418 this.mConversation = xmppConnectionService.findConversationByUuid(uuid);
419 if (this.mConversation != null) {
420 if (Compatibility.hasStoragePermission(this)) {
421 final int limit = GridManager.getCurrentColumnCount(this.binding.media);
422 xmppConnectionService.getAttachments(this.mConversation, limit, this);
423 this.binding.showMedia.setOnClickListener((v) -> MediaBrowserActivity.launch(this, mConversation));
424 }
425 updateView();
426 }
427 }
428 }
429
430 @Override
431 public void onBackPressed() {
432 if (this.binding.mucEditor.getVisibility() == View.VISIBLE) {
433 hideEditor();
434 } else {
435 super.onBackPressed();
436 }
437 }
438
439 private void updateView() {
440 invalidateOptionsMenu();
441 if (mConversation == null) {
442 return;
443 }
444 final MucOptions mucOptions = mConversation.getMucOptions();
445 final User self = mucOptions.getSelf();
446 String account;
447 if (Config.DOMAIN_LOCK != null) {
448 account = mConversation.getAccount().getJid().getEscapedLocal();
449 } else {
450 account = mConversation.getAccount().getJid().asBareJid().toEscapedString();
451 }
452 setTitle(mucOptions.isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details);
453 this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject()) ? View.VISIBLE : View.GONE);
454 this.binding.detailsAccount.setText(getString(R.string.using_account, account));
455 if (mConversation.isPrivateAndNonAnonymous()) {
456 this.binding.jid.setText(getString(R.string.hosted_on, mConversation.getJid().getDomain()));
457 } else {
458 this.binding.jid.setText(mConversation.getJid().asBareJid().toEscapedString());
459 }
460 AvatarWorkerTask.loadAvatar(mConversation, binding.yourPhoto, R.dimen.avatar_on_details_screen_size);
461 String roomName = mucOptions.getName();
462 String subject = mucOptions.getSubject();
463 final boolean hasTitle;
464 if (printableValue(roomName)) {
465 this.binding.mucTitle.setText(EmojiWrapper.transform(roomName));
466 this.binding.mucTitle.setVisibility(View.VISIBLE);
467 hasTitle = true;
468 } else if (!printableValue(subject)) {
469 this.binding.mucTitle.setText(EmojiWrapper.transform(mConversation.getName()));
470 hasTitle = true;
471 this.binding.mucTitle.setVisibility(View.VISIBLE);
472 } else {
473 hasTitle = false;
474 this.binding.mucTitle.setVisibility(View.GONE);
475 }
476 if (printableValue(subject)) {
477 SpannableStringBuilder spannable = new SpannableStringBuilder(subject);
478 StylingHelper.format(spannable, this.binding.mucSubject.getCurrentTextColor());
479 MyLinkify.addLinks(spannable, false);
480 this.binding.mucSubject.setText(EmojiWrapper.transform(spannable));
481 this.binding.mucSubject.setTextAppearance(this, subject.length() > (hasTitle ? 128 : 196) ? R.style.TextAppearance_Conversations_Body1_Linkified : R.style.TextAppearance_Conversations_Subhead);
482 this.binding.mucSubject.setAutoLinkMask(0);
483 this.binding.mucSubject.setVisibility(View.VISIBLE);
484 } else {
485 this.binding.mucSubject.setVisibility(View.GONE);
486 }
487 this.binding.mucYourNick.setText(mucOptions.getActualNick());
488 if (mucOptions.online()) {
489 this.binding.usersWrapper.setVisibility(View.VISIBLE);
490 this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
491 this.binding.mucRole.setVisibility(View.VISIBLE);
492 this.binding.mucRole.setText(getStatus(self));
493 if (mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER)) {
494 this.binding.mucSettings.setVisibility(View.VISIBLE);
495 this.binding.mucConferenceType.setText(MucConfiguration.describe(this, mucOptions));
496 } else if (!mucOptions.isPrivateAndNonAnonymous() && mucOptions.nonanonymous()) {
497 this.binding.mucSettings.setVisibility(View.VISIBLE);
498 this.binding.mucConferenceType.setText(R.string.group_chat_will_make_your_jabber_id_public);
499 } else {
500 this.binding.mucSettings.setVisibility(View.GONE);
501 }
502 if (mucOptions.mamSupport()) {
503 this.binding.mucInfoMam.setText(R.string.server_info_available);
504 } else {
505 this.binding.mucInfoMam.setText(R.string.server_info_unavailable);
506 }
507 if (self.getAffiliation().ranks(MucOptions.Affiliation.OWNER)) {
508 this.binding.changeConferenceButton.setVisibility(View.VISIBLE);
509 } else {
510 this.binding.changeConferenceButton.setVisibility(View.INVISIBLE);
511 }
512 } else {
513 this.binding.usersWrapper.setVisibility(View.GONE);
514 this.binding.mucInfoMore.setVisibility(View.GONE);
515 this.binding.mucSettings.setVisibility(View.GONE);
516 }
517
518 int ic_notifications = getThemeResource(R.attr.icon_notifications, R.drawable.ic_notifications_black_24dp);
519 int ic_notifications_off = getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp);
520 int ic_notifications_paused = getThemeResource(R.attr.icon_notifications_paused, R.drawable.ic_notifications_paused_black_24dp);
521 int ic_notifications_none = getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp);
522
523 long mutedTill = mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
524 if (mutedTill == Long.MAX_VALUE) {
525 this.binding.notificationStatusText.setText(R.string.notify_never);
526 this.binding.notificationStatusButton.setImageResource(ic_notifications_off);
527 } else if (System.currentTimeMillis() < mutedTill) {
528 this.binding.notificationStatusText.setText(R.string.notify_paused);
529 this.binding.notificationStatusButton.setImageResource(ic_notifications_paused);
530 } else if (mConversation.alwaysNotify()) {
531 this.binding.notificationStatusText.setText(R.string.notify_on_all_messages);
532 this.binding.notificationStatusButton.setImageResource(ic_notifications);
533 } else {
534 this.binding.notificationStatusText.setText(R.string.notify_only_when_highlighted);
535 this.binding.notificationStatusButton.setImageResource(ic_notifications_none);
536 }
537 final List<User> users = mucOptions.getUsers();
538 Collections.sort(users, (a, b) -> {
539 if (b.getAffiliation().outranks(a.getAffiliation())) {
540 return 1;
541 } else if (a.getAffiliation().outranks(b.getAffiliation())) {
542 return -1;
543 } else {
544 if (a.getAvatar() != null && b.getAvatar() == null) {
545 return -1;
546 } else if (a.getAvatar() == null && b.getAvatar() != null) {
547 return 1;
548 } else {
549 return a.getComparableName().compareToIgnoreCase(b.getComparableName());
550 }
551 }
552 });
553 this.mUserPreviewAdapter.submitList(MucOptions.sub(users, GridManager.getCurrentColumnCount(binding.users)));
554 this.binding.invite.setVisibility(mucOptions.canInvite() ? View.VISIBLE : View.GONE);
555 this.binding.showUsers.setVisibility(users.size() > 0 ? View.VISIBLE : View.GONE);
556 this.binding.showUsers.setText(getResources().getQuantityString(R.plurals.view_users, users.size(), users.size()));
557 this.binding.usersWrapper.setVisibility(users.size() > 0 || mucOptions.canInvite() ? View.VISIBLE : View.GONE);
558 if (users.size() == 0) {
559 this.binding.noUsersHints.setText(mucOptions.isPrivateAndNonAnonymous() ? R.string.no_users_hint_group_chat : R.string.no_users_hint_channel);
560 this.binding.noUsersHints.setVisibility(View.VISIBLE);
561 } else {
562 this.binding.noUsersHints.setVisibility(View.GONE);
563 }
564
565 }
566
567 public static String getStatus(Context context, User user, final boolean advanced) {
568 if (advanced) {
569 return String.format("%s (%s)", context.getString(user.getAffiliation().getResId()), context.getString(user.getRole().getResId()));
570 } else {
571 return context.getString(user.getAffiliation().getResId());
572 }
573 }
574
575 private String getStatus(User user) {
576 return getStatus(this, user, mAdvancedMode);
577 }
578
579
580 @Override
581 public void onAffiliationChangedSuccessful(Jid jid) {
582 refreshUi();
583 }
584
585 @Override
586 public void onAffiliationChangeFailed(Jid jid, int resId) {
587 displayToast(getString(resId, jid.asBareJid().toEscapedString()));
588 }
589
590 @Override
591 public void onRoomDestroySucceeded() {
592 finish();
593 }
594
595 @Override
596 public void onRoomDestroyFailed() {
597 final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous();
598 displayToast(getString(groupChat ? R.string.could_not_destroy_room : R.string.could_not_destroy_channel));
599 }
600
601 @Override
602 public void onPushSucceeded() {
603 displayToast(getString(R.string.modified_conference_options));
604 }
605
606 @Override
607 public void onPushFailed() {
608 displayToast(getString(R.string.could_not_modify_conference_options));
609 }
610
611 private void displayToast(final String msg) {
612 runOnUiThread(() -> {
613 if (isFinishing()) {
614 return;
615 }
616 ToastCompat.makeText(this, msg, Toast.LENGTH_SHORT).show();
617 });
618 }
619
620 @Override
621 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
622
623 }
624
625 @Override
626 public void onTextChanged(CharSequence s, int start, int before, int count) {
627
628 }
629
630 @Override
631 public void afterTextChanged(Editable s) {
632 if (mConversation == null) {
633 return;
634 }
635 final MucOptions mucOptions = mConversation.getMucOptions();
636 if (this.binding.mucEditor.getVisibility() == View.VISIBLE) {
637 boolean subjectChanged = changed(binding.mucEditSubject.getEditableText().toString(), mucOptions.getSubject());
638 boolean nameChanged = changed(binding.mucEditTitle.getEditableText().toString(), mucOptions.getName());
639 if (subjectChanged || nameChanged) {
640 this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_save, R.drawable.ic_save_black_24dp));
641 } else {
642 this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp));
643 }
644 }
645 }
646
647}