Add nav drawer with account switcher

Stephen Paul Weber created

Change summary

build.gradle                                                               |   1 
src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java         |  38 
src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java         | 195 
src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java |   4 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java     |  81 
src/main/java/eu/siacs/conversations/ui/XmppActivity.java                  |  12 
src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java   |   2 
src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java       |   2 
src/main/res/layout/activity_conversations.xml                             |  14 
src/main/res/layout/fragment_conversations_overview.xml                    |   1 
src/main/res/values/dimens.xml                                             |   1 
src/main/res/values/themes.xml                                             |   2 
12 files changed, 303 insertions(+), 50 deletions(-)

Detailed changes

build.gradle 🔗

@@ -124,6 +124,7 @@ dependencies {
     implementation 'me.xdrop:fuzzywuzzy:1.4.0'
     implementation 'net.fellbaum:jemoji:1.4.1'
     implementation 'com.github.natario1:Autocomplete:v1.1.0'
+    implementation 'com.mikepenz:materialdrawer:9.0.1'
 }
 
 ext {

src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java 🔗

@@ -156,6 +156,11 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
         }
     }
 
+    @Override
+    public boolean colorCodeAccounts() {
+        return mActivatedAccounts.size() > 1;
+    }
+
     @Override
     public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
         return false;
@@ -282,21 +287,23 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
             getListItemAdapter().notifyDataSetChanged();
             return;
         }
-        for (final Account account : xmppConnectionService.getAccounts()) {
-            if (account.isEnabled()) {
-                for (final Contact contact : account.getRoster().getContacts()) {
-                    if (contact.showInContactList() &&
-                            !filterContacts.contains(contact.getJid().asBareJid().toString())
-                            && contact.match(this, needle)) {
-                        getListItems().add(contact);
-                    }
+        final var accounts = new ArrayList<Account>();
+        for (final var account : xmppConnectionService.getAccounts()) {
+            if (mActivatedAccounts.contains(account.getJid().asBareJid().toEscapedString())) accounts.add(account);
+        }
+        for (final Account account : accounts) {
+            for (final Contact contact : account.getRoster().getContacts()) {
+                if (contact.showInContactList() &&
+                        !filterContacts.contains(contact.getJid().asBareJid().toString())
+                        && contact.match(this, needle)) {
+                    getListItems().add(contact);
                 }
+            }
 
-                final Contact self = new Contact(account.getSelfContact());
-                self.setSystemName("Note to Self");
-                if (self.match(this, needle)) {
-                    getListItems().add(self);
-                }
+            final Contact self = new Contact(account.getSelfContact());
+            self.setSystemName("Note to Self");
+            if (self.match(this, needle)) {
+                getListItems().add(self);
             }
         }
         Collections.sort(getListItems());
@@ -383,13 +390,14 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
 
     @Override
     protected void onBackendConnected() {
-        filterContacts();
         this.mActivatedAccounts.clear();
+        final var selected = getIntent().getStringExtra(EXTRA_ACCOUNT);
         for (final Account account : xmppConnectionService.getAccounts()) {
-            if (account.isEnabled()) {
+            if (account.isEnabled() && (selected == null || selected.equals(account.getJid().asBareJid().toEscapedString()))) {
                 this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
             }
         }
+        filterContacts();
         ActivityResult activityResult = this.postponedActivityResult.pop();
         if (activityResult != null) {
             handleActivityResult(activityResult);

src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java 🔗

@@ -98,6 +98,7 @@ import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
 import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
 import eu.siacs.conversations.ui.util.PendingItem;
 import eu.siacs.conversations.ui.util.ToolbarUtils;
+import eu.siacs.conversations.utils.AccountUtils;
 import eu.siacs.conversations.utils.ExceptionHelper;
 import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
 import eu.siacs.conversations.utils.SignupUtils;
@@ -134,6 +135,10 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     public static final int DIALLER_INTEGRATION = 0x5432ff;
     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;
 
     //secondary fragment (when holding the conversation, must be initialized before refreshing the overview fragment
     private static final @IdRes
@@ -146,6 +151,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     private boolean refreshForNewCaps = false;
     private Set<Jid> newCapsJids = new HashSet<>();
     private int mRequestCode = -1;
+    private com.mikepenz.materialdrawer.widget.AccountHeaderView accountHeader;
+    private Bundle savedState = null;
 
     private static boolean isViewOrShareIntent(Intent i) {
         Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction()));
@@ -167,10 +174,63 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
         }
         refreshForNewCaps = false;
         newCapsJids.clear();
+
+        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);
+        }
+
+        var hasPhoneAccounts = false;
+        accountHeader.removeProfileByIdentifier(DRAWER_MANAGE_PHONE_ACCOUNTS);
+        outer:
+        for (Account account : xmppConnectionService.getAccounts()) {
+            for (Contact contact : account.getRoster().getContacts()) {
+                if (contact.getPresences().anyIdentity("gateway", "pstn")) {
+                    hasPhoneAccounts = true;
+                    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);
+                    break outer;
+                }
+            }
+        }
+
+        int 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));
+            if (inHeader.contains(a)) {
+                accountHeader.updateProfile(p);
+            } else {
+                accountHeader.addProfile(p, accountHeader.getProfiles().size() - (hasPhoneAccounts ? 2 : 1));
+            }
+        }
     }
 
     @Override
     protected void onBackendConnected() {
+        final var useSavedState = savedState;
+        savedState = null;
         if (performRedirectIfNecessary(true)) {
             return;
         }
@@ -194,7 +254,6 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
             handleActivityResult(activityResult);
         }
 
-        invalidateActionBarTitle();
         if (binding.secondaryFragment != null && ConversationFragment.getConversation(this) == null) {
             Conversation conversation = ConversationsOverviewFragment.getSuggestion(this);
             if (conversation != null) {
@@ -202,6 +261,135 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
             }
         }
         showDialogsIfMainIsOverview();
+
+        if (accountHeader != null) {
+            refreshUiReal();
+            return;
+        }
+
+        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.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 settings = new com.mikepenz.materialdrawer.model.PrimaryDrawerItem();
+        settings.setIdentifier(DRAWER_SETTINGS);
+        settings.setSelectable(false);
+        com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(settings, "Settings");
+        com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconRes(settings, R.drawable.ic_settings_24dp);
+        com.mikepenz.materialdrawer.util.MaterialDrawerSliderViewExtensionsKt.addStickyDrawerItems(binding.drawer, settings);
+
+        refreshUiReal();
+        if (useSavedState != null) binding.drawer.setSavedInstance(useSavedState);
+        accountHeader.attachToSliderView(binding.drawer);
+        if (useSavedState != null) accountHeader.withSavedInstance(useSavedState);
+
+        if (binding.drawer.getSelectedItemPosition() < 1) {
+            binding.drawer.setSelectedItemIdentifier(DRAWER_ALL_CHATS);
+        }
+
+        binding.drawer.setOnDrawerItemClickListener((v, drawerItem, pos) -> {
+            final var id = drawerItem.getIdentifier();
+            if (id == DRAWER_SETTINGS) {
+                startActivity(new Intent(this, eu.siacs.conversations.ui.activity.SettingsActivity.class));
+            }
+            return false;
+        });
+
+         accountHeader.setOnAccountHeaderListener((v, profile, isCurrent) -> {
+            final var id = profile.getIdentifier();
+            if (isCurrent) return false; // Ignore switching to already selected profile
+
+            if (id == DRAWER_MANAGE_ACCOUNT) {
+                final Account account = (Account) accountHeader.getActiveProfile().getTag();
+                if (account == null) {
+                    AccountUtils.launchManageAccounts(this);
+                } else {
+                    switchToAccount(account);
+                }
+                return false;
+            }
+
+            if (id == DRAWER_MANAGE_PHONE_ACCOUNTS) {
+                final String[] permissions;
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                    permissions = new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.BLUETOOTH_CONNECT};
+                } else {
+                    permissions = new String[]{Manifest.permission.RECORD_AUDIO};
+                }
+                requestPermissions(permissions, REQUEST_MICROPHONE);
+                return false;
+            }
+
+            // Clicked on an actual profile
+            if (profile.getTag() == null) {
+                com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(manageAccount, "Manage Accounts");
+            } else {
+                com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(manageAccount, "Manage Account");
+            }
+            accountHeader.updateProfile(manageAccount);
+
+            final var fm = getFragmentManager();
+            while (fm.getBackStackEntryCount() > 0) {
+                try {
+                    fm.popBackStackImmediate();
+                } catch (IllegalStateException e) {
+                    break;
+                }
+            }
+
+            refreshUi();
+
+            return false;
+        });
+
+         accountHeader.setOnAccountHeaderProfileImageListener((v, profile, isCurrent) -> {
+            if (isCurrent) {
+                final Account account = (Account) accountHeader.getActiveProfile().getTag();
+                if (account == null) {
+                    AccountUtils.launchManageAccounts(this);
+                } else {
+                    switchToAccount(account);
+                }
+            }
+            return false;
+         });
+    }
+
+    @Override
+    public boolean colorCodeAccounts() {
+        if (accountHeader != null) {
+            final var active = accountHeader.getActiveProfile();
+            if (active != null && active.getTag() != null) return false;
+        }
+        return super.colorCodeAccounts();
+    }
+
+    @Override
+    public void populateWithOrderedConversations(List<Conversation> list) {
+        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);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void launchStartConversation() {
+        StartConversationActivity.launch(this, (Account) accountHeader.getActiveProfile().getTag());
     }
 
     private boolean performRedirectIfNecessary(boolean noAnimation) {
@@ -507,6 +695,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        savedState = savedInstanceState;
         ConversationMenuConfigurator.reloadFeatures(this);
         OmemoSetting.load(this);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_conversations);
@@ -725,9 +914,11 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     }
 
     @Override
-    public void onSaveInstanceState(final Bundle savedInstanceState) {
+    public void onSaveInstanceState(Bundle savedInstanceState) {
         final Intent pendingIntent = pendingViewIntent.peek();
         savedInstanceState.putParcelable("intent", pendingIntent != null ? pendingIntent : getIntent());
+        savedInstanceState = binding.drawer.saveInstanceState(savedInstanceState);
+        savedInstanceState = accountHeader.saveInstanceState(savedInstanceState);
         super.onSaveInstanceState(savedInstanceState);
     }
 

src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java 🔗

@@ -287,7 +287,7 @@ public class ConversationsOverviewFragment extends XmppFragment {
 	@Override
 	public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 		this.binding = DataBindingUtil.inflate(inflater, R.layout.fragment_conversations_overview, container, false);
-		this.binding.fab.setOnClickListener((view) -> StartConversationActivity.launch(getActivity()));
+		this.binding.fab.setOnClickListener((view) -> activity.launchStartConversation());
 
 		this.conversationsAdapter = new ConversationAdapter(this.activity, this.conversations);
 		this.conversationsAdapter.setConversationClickListener((view, conversation) -> {
@@ -479,7 +479,7 @@ public class ConversationsOverviewFragment extends XmppFragment {
 			Log.d(Config.LOGTAG,"ConversationsOverviewFragment.refresh() skipped updated because view binding or activity was null");
 			return;
 		}
-		this.activity.xmppConnectionService.populateWithOrderedConversations(this.conversations);
+		this.activity.populateWithOrderedConversations(this.conversations);
 		Conversation removed = this.swipedConversation.peek();
 		if (removed != null) {
 			if (removed.isRead()) {

src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java 🔗

@@ -123,6 +123,7 @@ public class StartConversationActivity extends XmppActivity
             "contact_list_integration_consent";
 
     public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri";
+    public static final String EXTRA_ACCOUNT_FILTER = "account_filter";
 
     private final int REQUEST_SYNC_CONTACTS = 0x28cf;
     private final int REQUEST_CREATE_CONFERENCE = 0x39da;
@@ -278,10 +279,24 @@ public class StartConversationActivity extends XmppActivity
     }
 
     public static void launch(Context context) {
+        launch(context, null);
+    }
+
+    public static void launch(Context context, final Account account) {
         final Intent intent = new Intent(context, StartConversationActivity.class);
+        if (account != null) {
+            intent.putExtra(
+                EXTRA_ACCOUNT_FILTER,
+                account.getJid().asBareJid().toEscapedString());
+        }
         context.startActivity(intent);
     }
 
+    @Override
+    public boolean colorCodeAccounts() {
+        return mActivatedAccounts.size() > 1;
+    }
+
     private static Intent createLauncherIntent(Context context) {
         final Intent intent = new Intent(context, StartConversationActivity.class);
         intent.setAction(Intent.ACTION_MAIN);
@@ -361,9 +376,10 @@ public class StartConversationActivity extends XmppActivity
 
         if (intent.getBooleanExtra("init", false)) {
             pendingViewIntent.push(intent);
-        }
-
-        if (isViewIntent(intent)) {
+        } else if(intent.hasExtra(EXTRA_ACCOUNT_FILTER)) {
+            pendingViewIntent.push(intent);
+            setIntent(intent);
+        } else if (isViewIntent(intent)) {
             pendingViewIntent.push(intent);
             createdByViewIntent = true;
             setIntent(createLauncherIntent(this));
@@ -1093,10 +1109,16 @@ public class StartConversationActivity extends XmppActivity
                     mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
             this.mPostponedActivityResult = null;
         }
+        var intent = pendingViewIntent.pop();
+        if (intent == null) intent = getIntent();
         this.mActivatedAccounts.clear();
-        this.mActivatedAccounts.addAll(AccountUtils.getEnabledAccounts(xmppConnectionService));
+        final String accountFilterJid = intent == null ? null : intent.getStringExtra(EXTRA_ACCOUNT_FILTER);
+        if (accountFilterJid == null) {
+            this.mActivatedAccounts.addAll(AccountUtils.getEnabledAccounts(xmppConnectionService));
+        } else {
+            this.mActivatedAccounts.add(accountFilterJid);
+        }
         configureHomeButton();
-        Intent intent = pendingViewIntent.pop();
 
         final boolean onboardingCancel = xmppConnectionService.getPreferences().getString("onboarding_action", "").equals("cancel");
         if (onboardingCancel) xmppConnectionService.getPreferences().edit().remove("onboarding_action").commit();
@@ -1286,36 +1308,37 @@ public class StartConversationActivity extends XmppActivity
     protected void filterContacts(String needle) {
         this.contacts.clear();
         ArrayList<ListItem.Tag> tags = new ArrayList<>();
-        final List<Account> accounts = xmppConnectionService.getAccounts();
+        final var accounts = new ArrayList<Account>();
+        for (final var account : xmppConnectionService.getAccounts()) {
+            if (mActivatedAccounts.contains(account.getJid().asBareJid().toEscapedString())) accounts.add(account);
+        }
         boolean foundSopranica = false;
         for (final Account account : accounts) {
-            if (account.isEnabled()) {
-                for (Contact contact : account.getRoster().getContacts()) {
-                    Presence.Status s = contact.getShownStatus();
-                    if (contact.showInContactList()
-                            && contact.match(this, needle)
-                            && (!this.mHideOfflineContacts
-                                    || (needle != null && !needle.trim().isEmpty())
-                                    || s.compareTo(Presence.Status.OFFLINE) < 0)) {
-                        this.contacts.add(contact);
-                        tags.addAll(contact.getTags(this));
-                    }
+            for (Contact contact : account.getRoster().getContacts()) {
+                Presence.Status s = contact.getShownStatus();
+                if (contact.showInContactList()
+                    && contact.match(this, needle)
+                    && (!this.mHideOfflineContacts
+                        || (needle != null && !needle.trim().isEmpty())
+                        || s.compareTo(Presence.Status.OFFLINE) < 0)) {
+                    this.contacts.add(contact);
+                    tags.addAll(contact.getTags(this));
                 }
+            }
 
-                final Contact self = new Contact(account.getSelfContact());
-                self.setSystemName("Note to Self");
-                if (self.match(this, needle)) {
-                    this.contacts.add(self);
-                }
+            final Contact self = new Contact(account.getSelfContact());
+            self.setSystemName("Note to Self");
+            if (self.match(this, needle)) {
+                this.contacts.add(self);
+            }
 
-                for (Bookmark bookmark : account.getBookmarks()) {
-                    if (bookmark.match(this, needle)) {
-                        if (bookmark.getJid().toString().equals("discuss@conference.soprani.ca")) {
-                            foundSopranica = true;
-                        }
-                        this.contacts.add(bookmark);
-                        tags.addAll(bookmark.getTags(this));
+            for (Bookmark bookmark : account.getBookmarks()) {
+                if (bookmark.match(this, needle)) {
+                    if (bookmark.getJid().toString().equals("discuss@conference.soprani.ca")) {
+                        foundSopranica = true;
                     }
+                    this.contacts.add(bookmark);
+                    tags.addAll(bookmark.getTags(this));
                 }
             }
         }

src/main/java/eu/siacs/conversations/ui/XmppActivity.java 🔗

@@ -560,6 +560,18 @@ public abstract class XmppActivity extends ActionBarActivity {
         startActivity(intent);
     }
 
+    public boolean colorCodeAccounts() {
+        return xmppConnectionService.getAccounts().size() > 1;
+    }
+
+    public void populateWithOrderedConversations(List<Conversation> list) {
+        xmppConnectionService.populateWithOrderedConversations(list);
+    }
+
+    public void launchStartConversation() {
+        StartConversationActivity.launch(this);
+    }
+
     public void switchToConversation(Conversation conversation) {
         switchToConversation(conversation, null);
     }

src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java 🔗

@@ -76,7 +76,7 @@ public class ConversationAdapter
                     R.drawable.background_selected_item_conversation);
             viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurfaceDim));
         } else {
-            if (activity.xmppConnectionService != null && activity.xmppConnectionService.getAccounts().size() > 1) {
+            if (activity.xmppConnectionService != null && activity.colorCodeAccounts()) {
                 viewHolder.binding.frame.setBackgroundColor(conversation.getAccount().getColor(activity.isDark()));
             } else {
                 viewHolder.binding.frame.setBackgroundColor(

src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java 🔗

@@ -81,7 +81,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
 		if (view.isActivated()) {
 			Log.d(Config.LOGTAG,"item "+item.getDisplayName()+" is activated");
 		}
-		if (activity.xmppConnectionService != null && activity.xmppConnectionService.getAccounts().size() > 1) {
+		if (activity.colorCodeAccounts()) {
 			innerView.setBackgroundColor(item.getAccount().getColor(activity.isDark()));
 		}
 		//view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));

src/main/res/layout/activity_conversations.xml 🔗

@@ -1,6 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android">
 
+    <androidx.drawerlayout.widget.DrawerLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:fitsSystemWindows="true">
+
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -23,4 +28,13 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent" />
     </LinearLayout>
+
+    <com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
+        android:id="@+id/drawer"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:fitsSystemWindows="true" />
+
+    </androidx.drawerlayout.widget.DrawerLayout>
 </layout>

src/main/res/values/dimens.xml 🔗

@@ -30,6 +30,7 @@
     <dimen name="image_radius">6dp</dimen>
     <dimen name="avatar_on_details_screen_size">56dp</dimen>
     <dimen name="avatar_on_conversation_overview">56dp</dimen>
+    <dimen name="avatar_on_drawer">128dp</dimen>
 
     <dimen name="input_label_vertical_spacing">4dp</dimen>
     <dimen name="input_label_horizontal_spacing">4dp</dimen>

src/main/res/values/themes.xml 🔗

@@ -50,5 +50,7 @@
         <item name="colorOnSurfaceInverse">@color/md_theme_light_inverseOnSurface</item>
         <item name="colorSurfaceInverse">@color/md_theme_light_inverseSurface</item>
         <item name="colorPrimaryInverse">@color/md_theme_light_inversePrimary</item>
+        <item name="materialDrawerStyle">@style/Widget.MaterialDrawerStyle</item>
+        <item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
     </style>
 </resources>