From f3f154a445bb79c04ef88000e80bc098a0635c6f Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Sat, 14 Sep 2024 23:26:35 -0500 Subject: [PATCH] Optimize drawer data loading We do it on every UI refresh so it matters. Stop refreshing accounts unless accounts have changed. Speed up tags dramatically by not bothering to sort the conversations (since we iterate them all anyway here). In my local testing this moved us from 20-26ms for the new code to an average of under 2ms. --- .../ui/ConversationsActivity.java | 179 ++++++++++-------- 1 file changed, 97 insertions(+), 82 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index e467a620c6447a8742841d2778906e395dda4da1..04ebcf87f9a06de8b5defa26f5ccbcdc30c1b757 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -169,6 +169,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio private Bundle savedState = null; private Tag selectedTag = null; private long mainFilter = DRAWER_ALL_CHATS; + private boolean refreshAccounts = true; private static boolean isViewOrShareIntent(Intent i) { Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction())); @@ -193,97 +194,106 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio if (accountHeader == null) return; - final var accounts = xmppConnectionService.getAccounts(); - final var inHeader = new HashSet<>(); - for (final var p : ImmutableList.copyOf(accountHeader.getProfiles())) { - if (p instanceof com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem) continue; - if (accounts.contains(p.getTag()) || (accounts.size() > 1 && p.getTag() == null)) { - inHeader.add(p.getTag()); - } else { - accountHeader.removeProfile(p); + accountHeader.apply(ah -> { + if (!refreshAccounts) return kotlin.Unit.INSTANCE; + refreshAccounts = false; + final var accounts = xmppConnectionService.getAccounts(); + final var inHeader = new HashSet<>(); + for (final var p : ImmutableList.copyOf(accountHeader.getProfiles())) { + if (p instanceof com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem) continue; + if (accounts.contains(p.getTag()) || (accounts.size() > 1 && p.getTag() == null)) { + inHeader.add(p.getTag()); + } else { + accountHeader.removeProfile(p); + } } - } - if (accounts.size() > 1 && !inHeader.contains(null)) { - final var all = new com.mikepenz.materialdrawer.model.ProfileDrawerItem(); - all.setIdentifier(100); - com.mikepenz.materialdrawer.model.interfaces.DescribableKt.setDescriptionText(all, "All Accounts"); - com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconRes(all, R.drawable.main_logo); - accountHeader.addProfile(all, 0); - } + if (accounts.size() > 1 && !inHeader.contains(null)) { + final var all = new com.mikepenz.materialdrawer.model.ProfileDrawerItem(); + all.setIdentifier(100); + com.mikepenz.materialdrawer.model.interfaces.DescribableKt.setDescriptionText(all, "All Accounts"); + com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconRes(all, R.drawable.main_logo); + accountHeader.addProfile(all, 0); + } - accountHeader.removeProfileByIdentifier(DRAWER_MANAGE_PHONE_ACCOUNTS); - final var hasPhoneAccounts = accounts.stream().anyMatch(a -> a.getGateways("pstn").size() > 0); - if (hasPhoneAccounts) { - final var phoneAccounts = new com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem(); - phoneAccounts.setIdentifier(DRAWER_MANAGE_PHONE_ACCOUNTS); - com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(phoneAccounts, "Manage Phone Accounts"); - com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconRes(phoneAccounts, R.drawable.ic_call_24dp); - accountHeader.addProfile(phoneAccounts, accountHeader.getProfiles().size() - 1); - } + accountHeader.removeProfileByIdentifier(DRAWER_MANAGE_PHONE_ACCOUNTS); + final var hasPhoneAccounts = accounts.stream().anyMatch(a -> a.getGateways("pstn").size() > 0); + if (hasPhoneAccounts) { + final var phoneAccounts = new com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem(); + phoneAccounts.setIdentifier(DRAWER_MANAGE_PHONE_ACCOUNTS); + com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(phoneAccounts, "Manage Phone Accounts"); + com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconRes(phoneAccounts, R.drawable.ic_call_24dp); + accountHeader.addProfile(phoneAccounts, accountHeader.getProfiles().size() - 1); + } - 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() == null ? "" : a.getDisplayName()); - com.mikepenz.materialdrawer.model.interfaces.DescribableKt.setDescriptionText(p, a.getJid().asBareJid().toString()); - 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)); + long id = 101; + for (final var a : accounts) { + final var avatar = xmppConnectionService.getAvatarService().get(a, (int) getResources().getDimension(R.dimen.avatar_on_drawer), false); + 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() == null ? "" : a.getDisplayName()); + com.mikepenz.materialdrawer.model.interfaces.DescribableKt.setDescriptionText(p, a.getJid().asBareJid().toString()); + if (avatar != null) com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconBitmap(p, FileBackend.drawDrawable(avatar).copy(Bitmap.Config.ARGB_8888, false)); + if (inHeader.contains(a)) { + accountHeader.updateProfile(p); + } else { + accountHeader.addProfile(p, accountHeader.getProfiles().size() - (hasPhoneAccounts ? 2 : 1)); + } } - } + return kotlin.Unit.INSTANCE; + }); - 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()); + binding.drawer.apply(dr -> { + final var items = binding.drawer.getItemAdapter().getAdapterItems(); + final var tags = new TreeMap(); + final var conversations = new ArrayList(); + populateWithOrderedConversations(conversations, false, 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; + long 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() : null; - 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()); - if (badge != null) com.mikepenz.materialdrawer.model.interfaces.BadgeableKt.setBadgeText(item, badge); - final var color = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorPrimaryContainer); - final var textColor = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorOnPrimaryContainer); - item.setBadgeStyle(new com.mikepenz.materialdrawer.holder.BadgeStyle(com.mikepenz.materialdrawer.R.drawable.material_drawer_badge, color, color, textColor)); - binding.drawer.getItemAdapter().add(binding.drawer.getItemAdapter().getGlobalPosition(4), item); + for (final var entry : tags.entrySet()) { + final var badge = entry.getValue() > 0 ? entry.getValue().toString() : null; + 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()); + if (badge != null) com.mikepenz.materialdrawer.model.interfaces.BadgeableKt.setBadgeText(item, badge); + final var color = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorPrimaryContainer); + final var textColor = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorOnPrimaryContainer); + item.setBadgeStyle(new com.mikepenz.materialdrawer.holder.BadgeStyle(com.mikepenz.materialdrawer.R.drawable.material_drawer_badge, color, color, textColor)); + binding.drawer.getItemAdapter().add(binding.drawer.getItemAdapter().getGlobalPosition(4), item); + } } - } - items.subList(4, 4 + tags.size()).sort((x, y) -> x.getTag() == null ? -1 : ((Comparable) x.getTag()).compareTo(y.getTag())); - binding.drawer.getItemAdapter().getFastAdapter().notifyDataSetChanged(); + items.subList(4, 4 + tags.size()).sort((x, y) -> x.getTag() == null ? -1 : ((Comparable) x.getTag()).compareTo(y.getTag())); + binding.drawer.getItemAdapter().getFastAdapter().notifyDataSetChanged(); + return kotlin.Unit.INSTANCE; + }); } @Override @@ -529,11 +539,15 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio @Override public void populateWithOrderedConversations(List list) { - populateWithOrderedConversations(list, true); + populateWithOrderedConversations(list, true, true); } - public void populateWithOrderedConversations(List list, final boolean tagFilter) { - super.populateWithOrderedConversations(list); + public void populateWithOrderedConversations(List list, final boolean tagFilter, final boolean sort) { + if (sort) { + super.populateWithOrderedConversations(list); + } else { + list.addAll(xmppConnectionService.getConversations()); + } if (accountHeader == null || accountHeader.getActiveProfile() == null) return; final var selectedAccount = @@ -1265,6 +1279,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio @Override public void onAccountUpdate() { + refreshAccounts = true; this.refreshUi(); }