diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 0672a372f0b9800b9723c22fd5ca0afb00ee160e..1122f4c52efa5ff15b7877d524758a31e36b5eeb 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -126,6 +126,7 @@ import eu.siacs.conversations.databinding.CommandTextFieldBinding; import eu.siacs.conversations.databinding.CommandSliderFieldBinding; import eu.siacs.conversations.databinding.CommandWebviewBinding; import eu.siacs.conversations.databinding.DialogQuickeditBinding; +import eu.siacs.conversations.entities.ListItem.Tag; import eu.siacs.conversations.http.HttpConnectionManager; import eu.siacs.conversations.persistance.DatabaseBackend; import eu.siacs.conversations.services.AvatarService; @@ -906,6 +907,15 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } } + public List getTags(final Context ctx) { + if (getMode() == MODE_MULTI) { + if (getBookmark() == null) return new ArrayList<>(); + return getBookmark().getTags(ctx); + } else { + return getContact().getTags(ctx); + } + } + public String getAccountUuid() { return this.accountUuid; } diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java index 201f651fd21bbd74ee43c7613f96b2d1a1c29dfd..f4a3a7bf3d75106f0df2076ffe22c25f66e33919 100644 --- a/src/main/java/eu/siacs/conversations/entities/ListItem.java +++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java @@ -20,7 +20,7 @@ public interface ListItem extends Comparable, AvatarService.Avatarable List getTags(Context context); - final class Tag implements Serializable { + final class Tag implements Serializable, Comparable { private final String name; public Tag(final String name) { @@ -41,6 +41,12 @@ public interface ListItem extends Comparable, AvatarService.Avatarable return name.toLowerCase(Locale.US).equals(ot.getName().toLowerCase(Locale.US)); } + public int compareTo(Object o) { + if (!(o instanceof Tag)) return -1; + Tag ot = (Tag) o; + return name.toLowerCase(Locale.US).compareTo(ot.getName().toLowerCase(Locale.US)); + } + public int hashCode() { return name.toLowerCase(Locale.US).hashCode(); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index 665c8b9aff837a5ddae7cc7789f853f045dc1169..e4e49d6dbcda245b166574638f639733cf36ee35 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -29,7 +29,6 @@ package eu.siacs.conversations.ui; - import static eu.siacs.conversations.ui.ConversationFragment.REQUEST_DECRYPT_PGP; import android.Manifest; @@ -43,6 +42,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -73,10 +73,13 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.openintents.openpgp.util.OpenPgpApi; import java.util.Arrays; +import java.util.ArrayList; import java.util.HashSet; +import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; import eu.siacs.conversations.Config; @@ -87,6 +90,8 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversational; +import eu.siacs.conversations.entities.ListItem.Tag; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.interfaces.OnBackendConnected; import eu.siacs.conversations.ui.interfaces.OnConversationArchived; @@ -136,9 +141,11 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio public static final int REQUEST_DOWNLOAD_STICKERS = 0xbf8702; public static final long DRAWER_ALL_CHATS = 1; - public static final long DRAWER_SETTINGS = 2; - public static final long DRAWER_MANAGE_ACCOUNT = 3; - public static final long DRAWER_MANAGE_PHONE_ACCOUNTS = 4; + public static final long DRAWER_DIRECT_MESSAGES = 2; + public static final long DRAWER_CHANNELS = 3; + public static final long DRAWER_SETTINGS = 4; + public static final long DRAWER_MANAGE_ACCOUNT = 5; + public static final long DRAWER_MANAGE_PHONE_ACCOUNTS = 6; //secondary fragment (when holding the conversation, must be initialized before refreshing the overview fragment private static final @IdRes @@ -153,6 +160,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio private int mRequestCode = -1; private com.mikepenz.materialdrawer.widget.AccountHeaderView accountHeader; private Bundle savedState = null; + private Tag selectedTag = null; + private long mainFilter = DRAWER_ALL_CHATS; private static boolean isViewOrShareIntent(Intent i) { Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction())); @@ -211,20 +220,62 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } } - int id = 101; + long id = 101; for (final var a : accounts) { final var p = new com.mikepenz.materialdrawer.model.ProfileDrawerItem(); p.setIdentifier(id++); p.setTag(a); com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(p, a.getDisplayName()); com.mikepenz.materialdrawer.model.interfaces.DescribableKt.setDescriptionText(p, a.getJid().asBareJid().toString()); - com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconDrawable(p, xmppConnectionService.getAvatarService().get(a, (int) getResources().getDimension(R.dimen.avatar_on_drawer), false)); + com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconBitmap(p, FileBackend.drawDrawable(xmppConnectionService.getAvatarService().get(a, (int) getResources().getDimension(R.dimen.avatar_on_drawer), false)).copy(Bitmap.Config.ARGB_8888, false)); if (inHeader.contains(a)) { accountHeader.updateProfile(p); } else { accountHeader.addProfile(p, accountHeader.getProfiles().size() - (hasPhoneAccounts ? 2 : 1)); } } + + final var items = binding.drawer.getItemAdapter().getAdapterItems(); + final var tags = new TreeMap(); + final var conversations = new ArrayList(); + populateWithOrderedConversations(conversations, false); + for (final var c : conversations) { + for (final var tag : c.getTags(this)) { + if ("Channel".equals(tag.getName())) continue; + var count = tags.get(tag); + if (count == null) count = 0; + tags.put(tag, count + c.unreadCount()); + } + } + + id = 1000; + final var inDrawer = new HashMap(); + for (final var item : ImmutableList.copyOf(items)) { + if (item.getIdentifier() >= 1000 && !tags.containsKey(item.getTag())) { + com.mikepenz.materialdrawer.util.MaterialDrawerSliderViewExtensionsKt.removeItems(binding.drawer, item); + } else if (item.getIdentifier() >= 1000) { + inDrawer.put((Tag)item.getTag(), item.getIdentifier()); + id = item.getIdentifier() + 1; + } + } + + for (final var entry : tags.entrySet()) { + final var badge = entry.getValue() > 0 ? entry.getValue().toString() : ""; + if (inDrawer.containsKey(entry.getKey())) { + com.mikepenz.materialdrawer.util.MaterialDrawerSliderViewExtensionsKt.updateBadge( + binding.drawer, + inDrawer.get(entry.getKey()), + new com.mikepenz.materialdrawer.holder.StringHolder(badge) + ); + } else { + final var item = new com.mikepenz.materialdrawer.model.SecondaryDrawerItem(); + item.setIdentifier(id++); + item.setTag(entry.getKey()); + com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(item, entry.getKey().getName()); + com.mikepenz.materialdrawer.model.interfaces.BadgeableKt.setBadgeText(item, badge); + binding.drawer.getItemAdapter().add(item); + } + } } @Override @@ -270,14 +321,29 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio accountHeader = new com.mikepenz.materialdrawer.widget.AccountHeaderView(this); final var manageAccount = new com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem(); manageAccount.setIdentifier(DRAWER_MANAGE_ACCOUNT); - com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(manageAccount, "Manage Accounts"); + com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(manageAccount, xmppConnectionService.getAccounts().size() > 1 ? "Manage Accounts" : "Manage Account"); com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconRes(manageAccount, R.drawable.ic_settings_24dp); accountHeader.addProfiles(manageAccount); - final var item = new com.mikepenz.materialdrawer.model.PrimaryDrawerItem(); - item.setIdentifier(DRAWER_ALL_CHATS); - com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(item, "All Chats"); - binding.drawer.getItemAdapter().add(item); + final var allChats = new com.mikepenz.materialdrawer.model.PrimaryDrawerItem(); + allChats.setIdentifier(DRAWER_ALL_CHATS); + com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(allChats, "All Chats"); + + + final var directMessages = new com.mikepenz.materialdrawer.model.PrimaryDrawerItem(); + directMessages.setIdentifier(DRAWER_DIRECT_MESSAGES); + com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(directMessages, "Direct Messages"); + + final var channels = new com.mikepenz.materialdrawer.model.PrimaryDrawerItem(); + channels.setIdentifier(DRAWER_CHANNELS); + com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(channels, "Channels"); + + binding.drawer.getItemAdapter().add( + allChats, + directMessages, + channels, + new com.mikepenz.materialdrawer.model.DividerDrawerItem() + ); final var settings = new com.mikepenz.materialdrawer.model.PrimaryDrawerItem(); settings.setIdentifier(DRAWER_SETTINGS); @@ -299,7 +365,15 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio final var id = drawerItem.getIdentifier(); if (id == DRAWER_SETTINGS) { startActivity(new Intent(this, eu.siacs.conversations.ui.activity.SettingsActivity.class)); + return false; + } else if (id == DRAWER_ALL_CHATS || id == DRAWER_DIRECT_MESSAGES || id == DRAWER_CHANNELS) { + selectedTag = null; + mainFilter = id; + } else if (id >= 1000) { + selectedTag = (Tag) drawerItem.getTag(); } + binding.drawer.getSelectExtension().selectByIdentifier(mainFilter, false, true); + refreshUi(); return false; }); @@ -374,22 +448,34 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio @Override public void populateWithOrderedConversations(List list) { + populateWithOrderedConversations(list, true); + } + + public void populateWithOrderedConversations(List list, final boolean tagFilter) { super.populateWithOrderedConversations(list); if (accountHeader == null || accountHeader.getActiveProfile() == null) return; - if (accountHeader.getActiveProfile().getTag() != null) { - final var selected = ((Account) accountHeader.getActiveProfile().getTag()).getUuid(); - for (final var c : ImmutableList.copyOf(list)) { - if (!selected.equals(c.getAccount().getUuid())) { - list.remove(c); - } + final var selectedAccount = + accountHeader.getActiveProfile().getTag() != null ? + ((Account) accountHeader.getActiveProfile().getTag()).getUuid() : + null; + + for (final var c : ImmutableList.copyOf(list)) { + if (mainFilter == DRAWER_CHANNELS && c.getMode() != Conversation.MODE_MULTI) { + list.remove(c); + } else if (mainFilter == DRAWER_DIRECT_MESSAGES && c.getMode() == Conversation.MODE_MULTI) { + list.remove(c); + } else if (selectedAccount != null && !selectedAccount.equals(c.getAccount().getUuid())) { + list.remove(c); + } else if (selectedTag != null && tagFilter && !c.getTags(this).contains(selectedTag)) { + list.remove(c); } } } @Override public void launchStartConversation() { - StartConversationActivity.launch(this, (Account) accountHeader.getActiveProfile().getTag()); + StartConversationActivity.launch(this, (Account) accountHeader.getActiveProfile().getTag(), selectedTag == null ? null : selectedTag.getName()); } private boolean performRedirectIfNecessary(boolean noAnimation) { diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 7ec4457bdf3a2cb2706199b5e671f17b09ad84fd..9322841ac6a66d3803b93521400dd5d88713fa70 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -124,6 +124,7 @@ public class StartConversationActivity extends XmppActivity public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri"; public static final String EXTRA_ACCOUNT_FILTER = "account_filter"; + public static final String EXTRA_TEXT_FILTER = "text_filter"; private final int REQUEST_SYNC_CONTACTS = 0x28cf; private final int REQUEST_CREATE_CONFERENCE = 0x39da; @@ -279,16 +280,19 @@ public class StartConversationActivity extends XmppActivity } public static void launch(Context context) { - launch(context, null); + launch(context, null, null); } - public static void launch(Context context, final Account account) { + public static void launch(Context context, final Account account, final String q) { final Intent intent = new Intent(context, StartConversationActivity.class); if (account != null) { intent.putExtra( EXTRA_ACCOUNT_FILTER, account.getJid().asBareJid().toEscapedString()); } + if (q != null) { + intent.putExtra(EXTRA_TEXT_FILTER, q); + } context.startActivity(intent); } @@ -365,6 +369,10 @@ public class StartConversationActivity extends XmppActivity final Intent intent; if (savedInstanceState == null) { intent = getIntent(); + final var search = intent.getStringExtra(EXTRA_TEXT_FILTER); + if (search != null) { + mInitialSearchValue.push(search); + } } else { createdByViewIntent = savedInstanceState.getBoolean("created_by_view_intent", false); final String search = savedInstanceState.getString("search"); diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index 29e1be10abc0cd8d75b0d582a065cabd1e45f127..73d08e2f9ea9e5840bb5ac5dc3790a6d2b7b72a4 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -53,4 +53,5 @@ @style/Widget.MaterialDrawerStyle @style/Widget.MaterialDrawerHeaderStyle +