diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 5653044d1fb65a6ea42098898dc9cffa85f6d47d..15872eafc1cbeaaa210f89d3a9733489c8d38f0f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -105,6 +105,11 @@ public class Bookmark extends Element implements ListItem { bookmark.setPassword(conference.findChildContent("password")); final Element extensions = conference.findChild("extensions", Namespace.BOOKMARKS2); if (extensions != null) { + for (final Element ext : extensions.getChildren()) { + if (ext.getName().equals("group") && ext.getNamespace().equals("jabber:iq:roster")) { + bookmark.addGroup(ext.getContent()); + } + } bookmark.extensions = extensions; } return bookmark; @@ -114,6 +119,31 @@ public class Bookmark extends Element implements ListItem { return extensions; } + public void addGroup(final String group) { + addChild("group", "jabber:iq:roster").setContent(group); + extensions.addChild("group", "jabber:iq:roster").setContent(group); + } + + public void setGroups(List groups) { + final List children = new ArrayList<>(getChildren()); + for (final Element el : children) { + if (el.getName().equals("group")) { + removeChild(el); + } + } + + final List extChildren = new ArrayList<>(extensions.getChildren()); + for (final Element el : extChildren) { + if (el.getName().equals("group")) { + extensions.removeChild(el); + } + } + + for (final String group : groups) { + addGroup(group); + } + } + public void setAutojoin(boolean autojoin) { if (autojoin) { this.setAttribute("autojoin", "true"); @@ -160,16 +190,24 @@ public class Bookmark extends Element implements ListItem { return jid == null || nick == null || nick.trim().isEmpty() ? jid : jid.withResource(nick); } - @Override - public List getTags(Context context) { + public List getGroupTags() { ArrayList tags = new ArrayList<>(); - tags.add(new Tag("Channel", UIHelper.getColorForName("Channel",true))); + for (Element element : getChildren()) { if (element.getName().equals("group") && element.getContent() != null) { String group = element.getContent(); - tags.add(new Tag(group, UIHelper.getColorForName(group,true))); + tags.add(new Tag(group, UIHelper.getColorForName(group, true))); } } + + return tags; + } + + @Override + public List getTags(Context context) { + ArrayList tags = new ArrayList<>(); + tags.add(new Tag("Channel", UIHelper.getColorForName("Channel",true))); + tags.addAll(getGroupTags()); return tags; } diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 20ef853ca39929bb9435a73df6693a4d7443a855..4d5eba0f706139164a5f47d32faa1e0f95e5717c 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -9,25 +9,34 @@ import android.text.Editable; import android.text.SpannableStringBuilder; import android.text.TextWatcher; import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; +import android.widget.ArrayAdapter; +import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; import androidx.databinding.DataBindingUtil; +import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ActivityMucDetailsBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Bookmark; +import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.User; import eu.siacs.conversations.services.XmppConnectionService; @@ -200,6 +209,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.mucEditTitle.addTextChangedListener(this); this.binding.mucEditSubject.addTextChangedListener(this); this.binding.mucEditSubject.addTextChangedListener(new StylingHelper.MessageEditorStyler(this.binding.mucEditSubject)); + this.binding.editTags.addTextChangedListener(this); this.mMediaAdapter = new MediaAdapter(this, R.dimen.media_size); this.mUserPreviewAdapter = new UserPreviewAdapter(); this.binding.media.setAdapter(mMediaAdapter); @@ -301,12 +311,52 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers if (!owner) { this.binding.mucEditSubject.requestFocus(); } + + final Bookmark bookmark = mConversation.getBookmark(); + if (bookmark != null && mConversation.getAccount().getXmppConnection().getFeatures().bookmarks2()) { + for (final ListItem.Tag group : bookmark.getGroupTags()) { + binding.editTags.addObjectSync(group); + } + ArrayList tags = new ArrayList<>(); + for (final Account account : xmppConnectionService.getAccounts()) { + for (Contact contact : account.getRoster().getContacts()) { + tags.addAll(contact.getTags(this)); + } + for (Bookmark bmark : account.getBookmarks()) { + tags.addAll(bmark.getTags(this)); + } + } + Comparator> sortTagsBy = Map.Entry.comparingByValue(Comparator.reverseOrder()); + sortTagsBy = sortTagsBy.thenComparing(entry -> entry.getKey().getName()); + + ArrayAdapter adapter = new ArrayAdapter<>( + this, + android.R.layout.simple_list_item_1, + tags.stream() + .collect(Collectors.toMap((x) -> x, (t) -> 1, (c1, c2) -> c1 + c2)) + .entrySet().stream() + .sorted(sortTagsBy) + .map(e -> e.getKey()).collect(Collectors.toList()) + ); + binding.editTags.setAdapter(adapter); + this.binding.editTags.setVisibility(View.VISIBLE); + } else { + this.binding.editTags.setVisibility(View.GONE); + } } else { String subject = this.binding.mucEditSubject.isEnabled() ? this.binding.mucEditSubject.getEditableText().toString().trim() : null; String name = this.binding.mucEditTitle.isEnabled() ? this.binding.mucEditTitle.getEditableText().toString().trim() : null; onMucInfoUpdated(subject, name); + + final Bookmark bookmark = mConversation.getBookmark(); + if (bookmark != null && mConversation.getAccount().getXmppConnection().getFeatures().bookmarks2()) { + bookmark.setGroups(binding.editTags.getObjects().stream().map(tag -> tag.getName()).collect(Collectors.toList())); + xmppConnectionService.createBookmark(bookmark.getAccount(), bookmark); + } + SoftKeyboardUtils.hideSoftKeyboard(this); hideEditor(); + updateView(); } } @@ -458,7 +508,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers account = mConversation.getAccount().getJid().asBareJid().toEscapedString(); } setTitle(mucOptions.isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details); - this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject()) ? View.VISIBLE : View.GONE); + final Bookmark bookmark = mConversation.getBookmark(); + this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject() || (bookmark != null && mConversation.getAccount().getXmppConnection().getFeatures().bookmarks2())) ? View.VISIBLE : View.GONE); this.binding.detailsAccount.setText(getString(R.string.using_account, account)); this.binding.truejid.setVisibility(View.GONE); if (mConversation.isPrivateAndNonAnonymous()) { @@ -574,6 +625,25 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.noUsersHints.setVisibility(View.GONE); } + if (bookmark == null) { + binding.tags.setVisibility(View.GONE); + return; + } + + List tagList = bookmark.getTags(this); + if (tagList.size() == 0) { + binding.tags.setVisibility(View.GONE); + } else { + final LayoutInflater inflater = getLayoutInflater(); + binding.tags.setVisibility(View.VISIBLE); + binding.tags.removeAllViewsInLayout(); + for (final ListItem.Tag tag : tagList) { + final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag, binding.tags, false); + tv.setText(tag.getName()); + tv.setBackgroundColor(tag.getColor()); + binding.tags.addView(tv); + } + } } public static String getStatus(Context context, User user, final boolean advanced) { @@ -648,7 +718,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers if (this.binding.mucEditor.getVisibility() == View.VISIBLE) { boolean subjectChanged = changed(binding.mucEditSubject.getEditableText().toString(), mucOptions.getSubject()); boolean nameChanged = changed(binding.mucEditTitle.getEditableText().toString(), mucOptions.getName()); - if (subjectChanged || nameChanged) { + final Bookmark bookmark = mConversation.getBookmark(); + if (subjectChanged || nameChanged || (bookmark != null && mConversation.getAccount().getXmppConnection().getFeatures().bookmarks2())) { this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_save, R.drawable.ic_save_black_24dp)); } else { this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp)); diff --git a/src/main/res/layout/activity_muc_details.xml b/src/main/res/layout/activity_muc_details.xml index 2706ac4339e6eae04b2190611d948909956794ab..418a3f23919a24028066e47414e255f4e0813e0d 100644 --- a/src/main/res/layout/activity_muc_details.xml +++ b/src/main/res/layout/activity_muc_details.xml @@ -86,6 +86,16 @@ android:layout_height="wrap_content" android:autoLink="web" android:textAppearance="@style/TextAppearance.Conversations.Subhead"/> + + + @@ -128,6 +138,13 @@ android:textAppearance="@style/Widget.Conversations.EditText"/> + +