From 180a85ed9b09ff6baad8b0adefdb6b7fdeac6a97 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Fri, 19 Feb 2016 23:38:31 +0100
Subject: [PATCH] Rewrote the drawer handling

---
 app/build.gradle                              |   1 +
 .../de/kuschku/libquassel/client/Client.java  |  13 +-
 .../libquassel/client/NetworkManager.java     |   1 -
 .../libquassel/localtypes/BacklogFilter.java  |   5 +-
 .../libquassel/localtypes/buffers/Buffer.java |   3 +-
 .../localtypes/buffers/ChannelBuffer.java     |   9 +-
 .../localtypes/buffers/QueryBuffer.java       |  11 +-
 .../localtypes/buffers/StatusBuffer.java      |   8 +-
 .../types/abstracts/AIgnoreListManager.java   |   5 +-
 .../types/impl/BufferViewConfig.java          |  20 ++
 .../types/interfaces/QBacklogManager.java     |   8 +-
 .../types/interfaces/QBufferViewConfig.java   |   4 +
 .../chat/BufferViewConfigSpinnerAdapter.java  | 125 ++++++++++
 .../ui/chat/ChannelDetailActivity.java        |  15 +-
 .../quasseldroid_ng/ui/chat/MainActivity.java | 154 ++++++------
 .../ui/chat/drawer/BufferItem.java            | 152 ------------
 .../ui/chat/drawer/BufferItemManager.java     |  81 -------
 .../chat/drawer/BufferViewConfigAdapter.java  | 226 ++++++++++++++++++
 .../ui/chat/drawer/BufferViewConfigItem.java  | 139 -----------
 .../ui/chat/drawer/BufferViewHolder.java      | 165 +++++++++++++
 .../ui/chat/drawer/NetworkItem.java           | 141 +++++------
 .../NetworkViewHolder.java}                   |  36 ++-
 .../ui/chat/drawer/NickListWrapper.java       | 152 ------------
 .../OnBufferClickListener.java}               |  15 +-
 .../ui/chat/util/LayoutHelperPhoneImpl.java   |  50 ----
 .../ui/chat/util/LayoutHelperTabletImpl.java  |  55 -----
 .../quasseldroid_ng/ui/theme/ThemeUtil.java   |  43 ++++
 app/src/main/res/drawable/badge.xml           |  30 +++
 .../main/res/layout-w720dp/activity_main.xml  |  42 +++-
 .../res/layout/activity_channel_detail.xml    |  30 +--
 app/src/main/res/layout/activity_main.xml     |  67 +++++-
 app/src/main/res/layout/fragment_chat.xml     |   3 +-
 app/src/main/res/layout/fragment_loading.xml  |   3 +-
 app/src/main/res/layout/widget_buffer.xml     | 103 ++++++++
 app/src/main/res/layout/widget_network.xml    |  55 +++++
 app/src/main/res/values/strings.xml           |   1 +
 36 files changed, 1101 insertions(+), 870 deletions(-)
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigSpinnerAdapter.java
 delete mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItem.java
 delete mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItemManager.java
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigAdapter.java
 delete mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigItem.java
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewHolder.java
 rename app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/{util/ILayoutHelper.java => drawer/NetworkViewHolder.java} (51%)
 delete mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NickListWrapper.java
 rename app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/{util/ActivityImplFactory.java => drawer/OnBufferClickListener.java} (70%)
 delete mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperPhoneImpl.java
 delete mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperTabletImpl.java
 create mode 100644 app/src/main/res/drawable/badge.xml
 create mode 100644 app/src/main/res/layout/widget_buffer.xml
 create mode 100644 app/src/main/res/layout/widget_network.xml

diff --git a/app/build.gradle b/app/build.gradle
index 7417cde86..4502d0f3e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -147,6 +147,7 @@ dependencies {
     compile 'org.joda:joda-convert:1.8'
 
     // UI Libs
+    compile 'com.bignerdranch.android:expandablerecyclerview:2.0.4'
     compile(name:'library-release', ext:'aar')
     compile('com.mikepenz:materialdrawer:5.0.0.b27-SNAPSHOT@aar') { transitive = true }
     compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') { transitive = true }
diff --git a/app/src/main/java/de/kuschku/libquassel/client/Client.java b/app/src/main/java/de/kuschku/libquassel/client/Client.java
index 0bb973ed7..09fd97c12 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/Client.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/Client.java
@@ -212,34 +212,32 @@ public class Client extends AClient {
     public Object unsafe_getObjectByIdentifier(@NonNull String className, @NonNull String objectName) {
         switch (className) {
             case "AliasManager": {
-                assertNotNull(aliasManager);
                 return aliasManager;
             }
             case "BacklogManager": {
-                assertNotNull(backlogManager);
                 return backlogManager;
             }
             case "BufferSyncer": {
-                assertNotNull(bufferSyncer);
                 return bufferSyncer;
             }
             case "BufferViewConfig": {
-                assertNotNull(bufferViewManager);
+                if (bufferViewManager == null)
+                    return null;
+
                 return bufferViewManager.bufferViewConfig(Integer.parseInt(objectName));
             }
             case "BufferViewManager": {
-                assertNotNull(bufferViewManager);
                 return bufferViewManager;
             }
             case "CoreInfo": {
-                assertNotNull(coreInfo);
                 return coreInfo;
             }
             case "Identity": {
+                if (identityManager == null)
+                    return null;
                 return identityManager.identity(Integer.parseInt(objectName));
             }
             case "IgnoreListManager": {
-                assertNotNull(ignoreListManager);
                 return ignoreListManager;
             }
             case "IrcChannel": {
@@ -272,7 +270,6 @@ public class Client extends AClient {
                 return networkManager.network(Integer.parseInt(objectName));
             }
             case "NetworkConfig": {
-                assertNotNull(globalNetworkConfig);
                 return globalNetworkConfig;
             }
             case "NetworkInfo": {
diff --git a/app/src/main/java/de/kuschku/libquassel/client/NetworkManager.java b/app/src/main/java/de/kuschku/libquassel/client/NetworkManager.java
index 27ca0a816..51e23bbde 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/NetworkManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/NetworkManager.java
@@ -68,7 +68,6 @@ public class NetworkManager extends Observable {
 
     public void init(@NonNull List<Integer> networkIds) {
         for (int networkId : networkIds) {
-            createNetwork(networkId);
             client.requestInitObject("Network", String.valueOf(networkId));
         }
     }
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java b/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java
index ffe87c6a6..340eedadb 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java
@@ -39,6 +39,8 @@ import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
 import de.kuschku.util.observables.callbacks.UICallback;
 import de.kuschku.util.observables.lists.ObservableComparableSortedList;
 
+import static de.kuschku.util.AndroidAssert.assertNotNull;
+
 public class BacklogFilter implements UICallback {
     @NonNull
     private final Client client;
@@ -92,7 +94,8 @@ public class BacklogFilter implements UICallback {
     }
 
     private boolean filterItem(@NonNull Message message) {
-        QNetwork network = client.networkManager().network(message.bufferInfo.networkId());
+        QNetwork network = client.networkManager().network(client.bufferManager().buffer(message.bufferInfo.id()).getInfo().networkId());
+        assertNotNull(network);
         return (client.ignoreListManager() != null && client.ignoreListManager().matches(message, network)) || filteredTypes.contains(message.type);
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffer.java b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffer.java
index 849f5d13d..67ec5c9b4 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffer.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffer.java
@@ -21,6 +21,7 @@
 
 package de.kuschku.libquassel.localtypes.buffers;
 
+import android.databinding.ObservableField;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
@@ -36,7 +37,7 @@ public interface Buffer {
     String getName();
 
     @NonNull
-    BufferInfo.BufferStatus getStatus();
+    ObservableField<BufferInfo.BufferStatus> getStatus();
 
     void renameBuffer(@NonNull String newName);
 
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/ChannelBuffer.java b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/ChannelBuffer.java
index fada32de0..cf00f0ce0 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/ChannelBuffer.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/ChannelBuffer.java
@@ -21,6 +21,7 @@
 
 package de.kuschku.libquassel.localtypes.buffers;
 
+import android.databinding.ObservableField;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
@@ -34,6 +35,8 @@ public class ChannelBuffer implements Buffer {
     @NonNull
     private BufferInfo info;
 
+    private ObservableField<BufferInfo.BufferStatus> status = new ObservableField<>();
+
     public ChannelBuffer(@NonNull BufferInfo info, @NonNull Client client) {
         this.info = info;
         this.client = client;
@@ -58,8 +61,10 @@ public class ChannelBuffer implements Buffer {
 
     @NonNull
     @Override
-    public BufferInfo.BufferStatus getStatus() {
-        return getChannel() == null ? BufferInfo.BufferStatus.OFFLINE : BufferInfo.BufferStatus.ONLINE;
+    public ObservableField<BufferInfo.BufferStatus> getStatus() {
+        // FIXME: Make this dynamic
+        status.set(getChannel() == null ? BufferInfo.BufferStatus.OFFLINE : BufferInfo.BufferStatus.ONLINE);
+        return status;
     }
 
     @Override
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/QueryBuffer.java b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/QueryBuffer.java
index e373eade1..89a507257 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/QueryBuffer.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/QueryBuffer.java
@@ -21,6 +21,7 @@
 
 package de.kuschku.libquassel.localtypes.buffers;
 
+import android.databinding.ObservableField;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
@@ -34,6 +35,8 @@ public class QueryBuffer implements Buffer {
     @NonNull
     private BufferInfo info;
 
+    private ObservableField<BufferInfo.BufferStatus> status = new ObservableField<>();
+
     public QueryBuffer(@NonNull BufferInfo info, @NonNull Client client) {
         this.info = info;
         this.client = client;
@@ -58,10 +61,12 @@ public class QueryBuffer implements Buffer {
 
     @NonNull
     @Override
-    public BufferInfo.BufferStatus getStatus() {
-        return (getUser() == null) ? BufferInfo.BufferStatus.OFFLINE :
+    public ObservableField<BufferInfo.BufferStatus> getStatus() {
+        // FIXME: Make this dynamic
+        status.set((getUser() == null) ? BufferInfo.BufferStatus.OFFLINE :
                 (getUser().isAway()) ? BufferInfo.BufferStatus.AWAY :
-                        BufferInfo.BufferStatus.ONLINE;
+                        BufferInfo.BufferStatus.ONLINE);
+        return status;
     }
 
     @Override
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/StatusBuffer.java b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/StatusBuffer.java
index ec75adde3..5828b6306 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/StatusBuffer.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/StatusBuffer.java
@@ -21,6 +21,7 @@
 
 package de.kuschku.libquassel.localtypes.buffers;
 
+import android.databinding.ObservableField;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
@@ -33,6 +34,7 @@ public class StatusBuffer implements Buffer {
     private final Client client;
     @NonNull
     private BufferInfo info;
+    private ObservableField<BufferInfo.BufferStatus> status = new ObservableField<>();
 
     public StatusBuffer(@NonNull BufferInfo info, @NonNull Client client) {
         this.info = info;
@@ -62,8 +64,10 @@ public class StatusBuffer implements Buffer {
 
     @NonNull
     @Override
-    public BufferInfo.BufferStatus getStatus() {
-        return getNetwork().isConnected() ? BufferInfo.BufferStatus.ONLINE : BufferInfo.BufferStatus.OFFLINE;
+    public ObservableField<BufferInfo.BufferStatus> getStatus() {
+        // FIXME: Make this dynamic
+        status.set(getNetwork().isConnected() ? BufferInfo.BufferStatus.ONLINE : BufferInfo.BufferStatus.OFFLINE);
+        return status;
     }
 
     @NonNull
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/abstracts/AIgnoreListManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/abstracts/AIgnoreListManager.java
index 9c8773597..2677b2004 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/abstracts/AIgnoreListManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/abstracts/AIgnoreListManager.java
@@ -28,6 +28,8 @@ import de.kuschku.libquassel.syncables.types.SyncableObject;
 import de.kuschku.libquassel.syncables.types.interfaces.QIgnoreListManager;
 import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
 
+import static de.kuschku.util.AndroidAssert.assertNotNull;
+
 public abstract class AIgnoreListManager<T extends AIgnoreListManager<T>> extends SyncableObject<T> implements QIgnoreListManager {
     @Override
     public void requestRemoveIgnoreListItem(String ignoreRule) {
@@ -76,7 +78,8 @@ public abstract class AIgnoreListManager<T extends AIgnoreListManager<T>> extend
     }
 
     @Override
-    public boolean matches(@NonNull Message message, @NonNull QNetwork network) {
+    public boolean matches(Message message, QNetwork network) {
+        assertNotNull(network);
         return match(message.content, message.sender, message.type, network.networkName(), message.bufferInfo.name()) != StrictnessType.UnmatchedStrictness;
     }
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewConfig.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewConfig.java
index 0fee0b05e..2c5f8ae23 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewConfig.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewConfig.java
@@ -32,6 +32,7 @@ import de.kuschku.libquassel.client.Client;
 import de.kuschku.libquassel.primitives.types.QVariant;
 import de.kuschku.libquassel.syncables.serializers.BufferViewConfigSerializer;
 import de.kuschku.libquassel.syncables.types.abstracts.ABufferViewConfig;
+import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
 import de.kuschku.util.observables.lists.ObservableList;
 import de.kuschku.util.observables.lists.ObservableSet;
 
@@ -46,6 +47,7 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
     private final ObservableSet<Integer> removedBuffers;
     @NonNull
     private final ObservableSet<Integer> temporarilyRemovedBuffers;
+    private final ObservableSet<QNetwork> networkList = new ObservableSet<>();
     private int bufferViewId;
     private String bufferViewName;
     private int networkId;
@@ -120,9 +122,21 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
     @Override
     public void _setNetworkId(int networkId) {
         this.networkId = networkId;
+        updateNetworks();
         _update();
     }
 
+    @Override
+    public void updateNetworks() {
+        if (this.networkId == 0) {
+            networkList.retainAll(client.networkManager().networks());
+            networkList.addAll(client.networkManager().networks());
+        } else {
+            networkList.retainAll(Collections.singleton(client.networkManager().network(this.networkId)));
+            networkList.add(client.networkManager().network(this.networkId));
+        }
+    }
+
     @Override
     public boolean addNewBuffersAutomatically() {
         return addNewBuffersAutomatically;
@@ -330,6 +344,7 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
         bufferViewId = Integer.parseInt(objectName);
         super.init(objectName, provider, client);
         client.bufferViewManager()._addBufferViewConfig(this);
+        updateNetworks();
         _update();
     }
 
@@ -338,6 +353,11 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
         bufferViewId = bufferViewConfigId;
     }
 
+    @Override
+    public ObservableSet<QNetwork> networkList() {
+        return networkList;
+    }
+
     @Override
     public void _update(@NonNull Map<String, QVariant> from) {
         _update(BufferViewConfigSerializer.get().fromLegacy(from));
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBacklogManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBacklogManager.java
index 9ab862b60..dcbadf289 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBacklogManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBacklogManager.java
@@ -42,9 +42,9 @@ public interface QBacklogManager<T extends QSyncableObject<T>> extends QSyncable
     void _requestBacklog(int id, int first, int last, int limit, int additional);
 
     @Synced
-    void receiveBacklog(int id, int first, int last, int limit, int additional, List<Message> messages);
+    void receiveBacklog(int id, int first, int last, int limit, int additional, @NonNull List<Message> messages);
 
-    void _receiveBacklog(int id, int first, int last, int limit, int additional, List<Message> messages);
+    void _receiveBacklog(int id, int first, int last, int limit, int additional, @NonNull List<Message> messages);
 
     @Synced
     void requestBacklogAll(int first, int last, int limit, int additional);
@@ -52,9 +52,9 @@ public interface QBacklogManager<T extends QSyncableObject<T>> extends QSyncable
     void _requestBacklogAll(int first, int last, int limit, int additional);
 
     @Synced
-    void receiveBacklogAll(int first, int last, int limit, int additional, List<Message> messages);
+    void receiveBacklogAll(int first, int last, int limit, int additional, @NonNull List<Message> messages);
 
-    void _receiveBacklogAll(int first, int last, int limit, int additional, List<Message> messages);
+    void _receiveBacklogAll(int first, int last, int limit, int additional, @NonNull List<Message> messages);
 
     @NonNull
     BacklogFilter filter(int id);
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewConfig.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewConfig.java
index 640099fc0..f73fe9ea1 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewConfig.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewConfig.java
@@ -152,4 +152,8 @@ public interface QBufferViewConfig extends QObservable {
     void _requestRemoveBufferPermanently(final int bufferId);
 
     void init(int bufferViewConfigId);
+
+    ObservableSet<QNetwork> networkList();
+
+    void updateNetworks();
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigSpinnerAdapter.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigSpinnerAdapter.java
new file mode 100644
index 000000000..7a1eda952
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigSpinnerAdapter.java
@@ -0,0 +1,125 @@
+/*
+ * QuasselDroid - Quassel client for Android
+ * Copyright (C) 2016 Janne Koschinski
+ * Copyright (C) 2016 Ken Børge Viktil
+ * Copyright (C) 2016 Magnus Fjell
+ * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid_ng.ui.chat;
+
+import android.content.res.Resources;
+import android.database.DataSetObserver;
+import android.support.annotation.Nullable;
+import android.support.v7.view.ContextThemeWrapper;
+import android.support.v7.widget.ThemedSpinnerAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewConfig;
+import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewManager;
+import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
+
+public class BufferViewConfigSpinnerAdapter implements ThemedSpinnerAdapter {
+    private final AppContext context;
+    private final QBufferViewManager bufferViewManager;
+    @Nullable
+    private Resources.Theme theme;
+
+    private Set<DataSetObserver> observers = new HashSet<>();
+
+    public BufferViewConfigSpinnerAdapter(AppContext context, QBufferViewManager bufferViewManager) {
+        this.context = context;
+        this.bufferViewManager = bufferViewManager;
+    }
+
+    @Nullable
+    @Override
+    public Resources.Theme getDropDownViewTheme() {
+        return theme;
+    }
+
+    @Override
+    public void setDropDownViewTheme(@Nullable Resources.Theme theme) {
+        this.theme = theme;
+    }
+
+    @Override
+    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+        LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(parent.getContext(), theme));
+        TextView view = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
+        view.setText(((QBufferViewConfig) getItem(position)).bufferViewName());
+        return view;
+    }
+
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        observers.add(observer);
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        observers.remove(observer);
+    }
+
+    @Override
+    public int getCount() {
+        return bufferViewManager.bufferViewConfigs().size();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return bufferViewManager.bufferViewConfigs().get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return ((QBufferViewConfig) getItem(position)).bufferViewId();
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(parent.getContext(), theme));
+        TextView view = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
+        view.setText(((QBufferViewConfig) getItem(position)).bufferViewName());
+        return view;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return 0;
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        return 1;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return getCount() == 0;
+    }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChannelDetailActivity.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChannelDetailActivity.java
index 01c7d2e16..05746007d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChannelDetailActivity.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChannelDetailActivity.java
@@ -21,6 +21,7 @@
 
 package de.kuschku.quasseldroid_ng.ui.chat;
 
+import android.graphics.Typeface;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.AppCompatButton;
@@ -30,7 +31,6 @@ import android.util.Log;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import butterknife.Bind;
 import butterknife.ButterKnife;
@@ -77,9 +77,16 @@ public class ChannelDetailActivity extends BoundActivity {
         QIrcChannel channel = buffer.getChannel();
         if (channel == null) return;
 
-        if (channel.topic() != null)
-        topic.setText(new IrcFormatHelper(context).formatIrcMessage(context.client(), channel.topic(), buffer.getInfo(), v -> finish()));
-        topic.setMovementMethod(LinkMovementMethod.getInstance());
+        if (channel.topic() == null) {
+            topic.setText(R.string.no_topic_set);
+            topic.setTextColor(context.themeUtil().res.colorForegroundSecondary);
+            topic.setTypeface(Typeface.defaultFromStyle(Typeface.ITALIC));
+        } else {
+            topic.setText(new IrcFormatHelper(context).formatIrcMessage(context.client(), channel.topic(), buffer.getInfo(), v -> finish()));
+            topic.setMovementMethod(LinkMovementMethod.getInstance());
+            topic.setTextColor(context.themeUtil().res.colorForeground);
+            topic.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
+        }
 
         toolbar.setTitle(channel.name());
         setSupportActionBar(toolbar);
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java
index cc112f621..4295df4a8 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MainActivity.java
@@ -23,24 +23,26 @@ package de.kuschku.quasseldroid_ng.ui.chat;
 
 import android.content.Intent;
 import android.os.Bundle;
-import android.support.annotation.IntRange;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.widget.AppCompatEditText;
+import android.support.v7.widget.AppCompatSpinner;
+import android.support.v7.widget.DefaultItemAnimator;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.Toolbar;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.widget.FrameLayout;
+import android.widget.AdapterView;
 import android.widget.Toast;
 
 import com.afollestad.materialdialogs.MaterialDialog;
-import com.mikepenz.materialdrawer.AccountHeader;
-import com.mikepenz.materialdrawer.AccountHeaderBuilder;
-import com.mikepenz.materialdrawer.Drawer;
-import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -60,19 +62,13 @@ import de.kuschku.libquassel.localtypes.buffers.ChannelBuffer;
 import de.kuschku.libquassel.localtypes.buffers.QueryBuffer;
 import de.kuschku.libquassel.message.Message;
 import de.kuschku.libquassel.syncables.types.interfaces.QBacklogManager;
-import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewConfig;
-import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewManager;
 import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel;
 import de.kuschku.libquassel.syncables.types.interfaces.QIrcUser;
 import de.kuschku.quasseldroid_ng.R;
 import de.kuschku.quasseldroid_ng.service.ClientBackgroundThread;
-import de.kuschku.quasseldroid_ng.ui.chat.drawer.BufferItem;
-import de.kuschku.quasseldroid_ng.ui.chat.drawer.BufferViewConfigItem;
-import de.kuschku.quasseldroid_ng.ui.chat.drawer.NetworkItem;
+import de.kuschku.quasseldroid_ng.ui.chat.drawer.BufferViewConfigAdapter;
 import de.kuschku.quasseldroid_ng.ui.chat.fragment.ChatFragment;
 import de.kuschku.quasseldroid_ng.ui.chat.fragment.LoadingFragment;
-import de.kuschku.quasseldroid_ng.ui.chat.util.ActivityImplFactory;
-import de.kuschku.quasseldroid_ng.ui.chat.util.ILayoutHelper;
 import de.kuschku.quasseldroid_ng.ui.chat.util.Status;
 import de.kuschku.util.accounts.Account;
 import de.kuschku.util.accounts.AccountManager;
@@ -83,17 +79,21 @@ import de.kuschku.util.servicebound.BoundActivity;
 import static de.kuschku.util.AndroidAssert.assertNotNull;
 
 public class MainActivity extends BoundActivity {
-
-    /**
-     * A helper to handle the different layout implementations
-     */
-    ILayoutHelper layoutHelper;
-
     /**
      * Host layout for content fragment, for example showing a loader or the chat
      */
-    @Bind(R.id.content_host)
-    FrameLayout contentHost;
+    @Bind(R.id.chatList)
+    RecyclerView chatList;
+
+    @Bind(R.id.chatListSpinner)
+    AppCompatSpinner chatListSpinner;
+
+    @Bind(R.id.chatListToolbar)
+    Toolbar chatListToolbar;
+
+    @Nullable
+    @Bind(R.id.drawer_layout)
+    DrawerLayout drawerLayout;
 
     /**
      * Main ActionBar
@@ -101,28 +101,17 @@ public class MainActivity extends BoundActivity {
     @Bind(R.id.toolbar)
     Toolbar toolbar;
 
-    /**
-     * The left material drawer of this activity, depending on layout either in the layout hierarchy
-     * or at the left as pull-out menu
-     */
-    Drawer drawerLeft;
-
-    /**
-     * AccountHeader field for the bufferviewconfig header
-     */
-    AccountHeader accountHeader;
-
     /**
      * This object encapsulates the current status of the activity – opened bufferview, for example
      */
     private Status status = new Status();
 
-    private BufferViewConfigItem currentConfig;
-
     private AccountManager manager;
 
     private ToolbarWrapper toolbarWrapper;
 
+    private BufferViewConfigAdapter chatListAdapter;
+
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -131,26 +120,33 @@ public class MainActivity extends BoundActivity {
         toolbarWrapper = new ToolbarWrapper(toolbar);
         toolbarWrapper.setOnClickListener(v -> {
             if (context.client() != null) {
-                Intent intent = new Intent(this, ChannelDetailActivity.class);
-                intent.putExtra("buffer", context.client().backlogManager().open());
-                startActivity(intent);
+                int id = context.client().backlogManager().open();
+                Buffer buffer = context.client().bufferManager().buffer(id);
+                if (buffer instanceof ChannelBuffer) {
+                    Intent intent = new Intent(this, ChannelDetailActivity.class);
+                    intent.putExtra("buffer", id);
+                    startActivity(intent);
+                }
             }
         });
         setSupportActionBar(toolbar);
-        layoutHelper = ActivityImplFactory.of(getResources().getBoolean(R.bool.isTablet), this);
-        accountHeader = buildAccountHeader();
-        drawerLeft = layoutHelper.buildDrawer(savedInstanceState, accountHeader, toolbar);
-        drawerLeft.setOnDrawerItemClickListener((view, position, drawerItem) -> {
-            if (drawerItem instanceof NetworkItem) {
-                drawerLeft.getAdapter().toggleExpandable(position);
-                return true;
-            } else if (drawerItem instanceof BufferItem) {
-                int id = ((BufferItem) drawerItem).getBuffer().getInfo().id();
-                context.client().backlogManager().open(id);
-                return false;
+        chatListAdapter = BufferViewConfigAdapter.of(context);
+        chatListAdapter.setBufferClickListener(buffer -> {
+            if (context.client() != null) {
+                context.client().backlogManager().open(buffer.getInfo().id());
+                if (drawerLayout != null)
+                    drawerLayout.closeDrawer(GravityCompat.START);
             }
-            return true;
         });
+        chatList.setItemAnimator(new DefaultItemAnimator());
+        chatList.setLayoutManager(new LinearLayoutManager(this));
+        chatList.setAdapter(chatListAdapter);
+
+        DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+        if (drawerLayout != null) {
+            ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.material_drawer_open, R.string.material_drawer_close);
+            toggle.syncState();
+        }
 
         replaceFragment(new LoadingFragment());
 
@@ -222,6 +218,8 @@ public class MainActivity extends BoundActivity {
         finish();
     }
 
+    /*
+
     private AccountHeader buildAccountHeader() {
         return new AccountHeaderBuilder()
                 .withActivity(this)
@@ -235,16 +233,16 @@ public class MainActivity extends BoundActivity {
                 .build();
     }
 
+    */
+
     public void onEventMainThread(ConnectionChangeEvent event) {
         onConnectionChange(event.status);
     }
 
     public void onConnectionChange(ConnectionChangeEvent.Status status) {
         if (status == ConnectionChangeEvent.Status.CONNECTED) {
-            updateBufferViewConfigs();
-            context.client().backlogManager().open(this.status.bufferId);
-            accountHeader.setActiveProfile(this.status.bufferViewConfigId, true);
             replaceFragment(new ChatFragment());
+            onConnected();
         } else if (status == ConnectionChangeEvent.Status.DISCONNECTED) {
             Toast.makeText(getApplication(), context.themeUtil().translations.statusDisconnected, Toast.LENGTH_LONG).show();
         }
@@ -289,33 +287,10 @@ public class MainActivity extends BoundActivity {
                 }
             }
         }
-        drawerLeft.setSelection(id, false);
     }
 
-    private void selectBufferViewConfig(@IntRange(from = -1) int bufferViewConfigId) {
-        assertNotNull(drawerLeft);
-        assertNotNull(accountHeader);
-        Client client = context.client();
-        assertNotNull(client);
-
-        drawerLeft.removeAllItems();
-
-        status.bufferViewConfigId = bufferViewConfigId;
-        accountHeader.setActiveProfile(bufferViewConfigId, false);
-
-        if (currentConfig != null)
-            currentConfig.remove();
-        currentConfig = null;
-
-        QBufferViewManager bufferViewManager = client.bufferViewManager();
-        if (bufferViewConfigId != -1 && bufferViewManager != null) {
-            QBufferViewConfig viewConfig = bufferViewManager.bufferViewConfig(bufferViewConfigId);
-            if (viewConfig != null) {
-                currentConfig = new BufferViewConfigItem(drawerLeft, viewConfig, context);
-            }
-        }
-    }
 
+    /*
     private void updateBufferViewConfigs() {
         assertNotNull(context.client().bufferViewManager());
         List<QBufferViewConfig> bufferViews = context.client().bufferViewManager().bufferViewConfigs();
@@ -334,6 +309,7 @@ public class MainActivity extends BoundActivity {
         }
         accountHeader.setActiveProfile(status.bufferViewConfigId, true);
     }
+    */
 
     @Override
     protected void onConnectToThread(@Nullable ClientBackgroundThread thread) {
@@ -342,14 +318,32 @@ public class MainActivity extends BoundActivity {
             connectToServer(manager.account(context.settings().lastAccount.get()));
         else {
             if (context.client() != null) {
-                context.client().backlogManager().init("", context.provider(), context.client());
-                context.client().backlogManager().open(status.bufferId);
-                updateBuffer(context.client().backlogManager().open());
-                accountHeader.setActiveProfile(status.bufferViewConfigId, true);
+                onConnected();
             }
         }
     }
 
+    private void onConnected() {
+        context.client().backlogManager().init("", context.provider(), context.client());
+        context.client().backlogManager().open(status.bufferId);
+        if (context.client().bufferViewManager() != null) {
+            chatListSpinner.setAdapter(new BufferViewConfigSpinnerAdapter(context, context.client().bufferViewManager()));
+            chatListSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+                @Override
+                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                    chatListAdapter.selectConfig((int) id);
+                }
+
+                @Override
+                public void onNothingSelected(AdapterView<?> parent) {
+                    chatListAdapter.selectConfig(-1);
+                }
+            });
+        }
+        updateBuffer(context.client().backlogManager().open());
+        // accountHeader.setActiveProfile(status.bufferViewConfigId, true);
+    }
+
     // FIXME: Fix this ugly hack
     public void displayFilterDialog() {
         if (context.client() != null) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItem.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItem.java
deleted file mode 100644
index dd27587a6..000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItem.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * QuasselDroid - Quassel client for Android
- * Copyright (C) 2016 Janne Koschinski
- * Copyright (C) 2016 Ken Børge Viktil
- * Copyright (C) 2016 Magnus Fjell
- * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.kuschku.quasseldroid_ng.ui.chat.drawer;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.view.View;
-import android.widget.TextView;
-
-import com.mikepenz.materialdrawer.holder.ColorHolder;
-import com.mikepenz.materialdrawer.holder.ImageHolder;
-import com.mikepenz.materialdrawer.holder.StringHolder;
-import com.mikepenz.materialdrawer.model.SecondaryDrawerItem;
-import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
-
-import de.kuschku.libquassel.localtypes.buffers.Buffer;
-import de.kuschku.libquassel.localtypes.buffers.ChannelBuffer;
-import de.kuschku.libquassel.localtypes.buffers.QueryBuffer;
-import de.kuschku.libquassel.localtypes.buffers.StatusBuffer;
-import de.kuschku.libquassel.message.Message;
-import de.kuschku.libquassel.primitives.types.BufferInfo;
-import de.kuschku.quasseldroid_ng.R;
-import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
-
-public class BufferItem extends SecondaryDrawerItem {
-    @NonNull
-    private final Buffer buffer;
-    @NonNull
-    private final AppContext context;
-
-    public BufferItem(@NonNull Buffer buffer, @NonNull AppContext context) {
-        this.buffer = buffer;
-        this.context = context;
-    }
-
-    @Override
-    public StringHolder getDescription() {
-        if (buffer instanceof QueryBuffer) {
-            QueryBuffer queryBuffer = (QueryBuffer) buffer;
-            if (queryBuffer.getUser() != null)
-                return new StringHolder(queryBuffer.getUser().realName());
-        } else if (buffer instanceof StatusBuffer) {
-
-        } else if (buffer instanceof ChannelBuffer) {
-            ChannelBuffer channelBuffer = (ChannelBuffer) buffer;
-            if (channelBuffer.getChannel() != null)
-                return new StringHolder(channelBuffer.getChannel().topic());
-        }
-        return super.getDescription();
-    }
-
-    @Nullable
-    @Override
-    public StringHolder getName() {
-        if (buffer instanceof StatusBuffer)
-            return new StringHolder(context.themeUtil().translations.titleStatusBuffer);
-        else
-            return new StringHolder(buffer.getName());
-    }
-
-    @NonNull
-    @Override
-    public ImageHolder getIcon() {
-        if (buffer instanceof ChannelBuffer) {
-            if (buffer.getStatus() != BufferInfo.BufferStatus.OFFLINE) {
-                return new ImageHolder(R.drawable.ic_status_channel);
-            } else {
-                return new ImageHolder(R.drawable.ic_status_channel_offline);
-            }
-        } else if (buffer instanceof StatusBuffer) {
-            if (buffer.getStatus() != BufferInfo.BufferStatus.OFFLINE) {
-                return new ImageHolder(R.drawable.ic_status);
-            } else {
-                return new ImageHolder(R.drawable.ic_status_offline);
-            }
-        } else {
-            if (buffer.getStatus() != BufferInfo.BufferStatus.OFFLINE) {
-                return new ImageHolder(R.drawable.ic_status);
-            } else {
-                return new ImageHolder(R.drawable.ic_status_offline);
-            }
-        }
-    }
-
-    @Override
-    public boolean isIconTinted() {
-        return buffer.getStatus() == BufferInfo.BufferStatus.ONLINE;
-    }
-
-    @NonNull
-    @Override
-    public ColorHolder getIconColor() {
-        return buffer.getStatus() == BufferInfo.BufferStatus.ONLINE ?
-                ColorHolder.fromColor(context.themeUtil().res.colorAccent) :
-                new ColorHolder();
-    }
-
-    @NonNull
-    @Override
-    public ColorHolder getDescriptionTextColor() {
-        return ColorHolder.fromColor(context.themeUtil().res.colorForegroundSecondary);
-    }
-
-    @NonNull
-    @Override
-    public ColorHolder getTextColor() {
-        int type = context.client().bufferSyncer().activity(buffer.getInfo().id());
-        if ((type & Message.Type.Plain.value) != 0 || (type & Message.Type.Notice.value) != 0)
-            return ColorHolder.fromColor(context.themeUtil().res.colorTintMessage);
-        else if ((type & ~Message.Type.DayChange.value) != 0)
-            return ColorHolder.fromColor(context.themeUtil().res.colorTintActivity);
-        else
-            return ColorHolder.fromColor(context.themeUtil().res.colorForeground);
-    }
-
-    @NonNull
-    public Buffer getBuffer() {
-        return buffer;
-    }
-
-    @Override
-    public long getIdentifier() {
-        return buffer.getInfo().id();
-    }
-
-    @Override
-    public void onPostBindView(IDrawerItem drawerItem, View view) {
-        super.onPostBindView(drawerItem, view);
-
-        if (getDescription() != null && getDescription().getText() != null)
-            ((TextView) view.findViewById(R.id.material_drawer_description)).setText(context.deserializer().formatString(getDescription().getText()));
-    }
-}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItemManager.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItemManager.java
deleted file mode 100644
index b4e597569..000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItemManager.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * QuasselDroid - Quassel client for Android
- * Copyright (C) 2016 Janne Koschinski
- * Copyright (C) 2016 Ken Børge Viktil
- * Copyright (C) 2016 Magnus Fjell
- * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.kuschku.quasseldroid_ng.ui.chat.drawer;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
-import de.kuschku.util.observables.IObservable;
-import de.kuschku.util.observables.callbacks.ElementCallback;
-import de.kuschku.util.observables.callbacks.wrappers.MultiElementCallbackWrapper;
-
-public class BufferItemManager implements ElementCallback<Integer>, IObservable<ElementCallback<BufferItem>> {
-
-    private final MultiElementCallbackWrapper<BufferItem> callback = MultiElementCallbackWrapper.<BufferItem>of();
-
-    @Nullable
-    private final AppContext context;
-    private final Map<Integer, BufferItem> items = new HashMap<>();
-
-    public BufferItemManager(@Nullable AppContext context) {
-        this.context = context;
-        context.client().bufferManager().bufferIds().addCallback(this);
-        for (Integer id : context.client().bufferManager().bufferIds()) {
-            notifyItemInserted(id);
-        }
-    }
-
-    public BufferItem get(int bufferId) {
-        return items.get(bufferId);
-    }
-
-    @Override
-    public void notifyItemInserted(Integer element) {
-        if (!items.containsKey(element)) {
-            BufferItem item = new BufferItem(context.client().bufferManager().buffer(element), context);
-            items.put(element, item);
-            callback.notifyItemInserted(item);
-        }
-    }
-
-    @Override
-    public void notifyItemRemoved(Integer element) {
-        callback.notifyItemRemoved(items.remove(element));
-    }
-
-    @Override
-    public void notifyItemChanged(Integer element) {
-        callback.notifyItemChanged(items.get(element));
-    }
-
-    public void addCallback(@NonNull ElementCallback<BufferItem> callback) {
-        this.callback.addCallback(callback);
-    }
-
-    public void removeCallback(@NonNull ElementCallback<BufferItem> callback) {
-        this.callback.removeCallback(callback);
-    }
-}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigAdapter.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigAdapter.java
new file mode 100644
index 000000000..2d1983fa4
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigAdapter.java
@@ -0,0 +1,226 @@
+/*
+ * QuasselDroid - Quassel client for Android
+ * Copyright (C) 2016 Janne Koschinski
+ * Copyright (C) 2016 Ken Børge Viktil
+ * Copyright (C) 2016 Magnus Fjell
+ * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid_ng.ui.chat.drawer;
+
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.bignerdranch.expandablerecyclerview.Adapter.ExpandableRecyclerAdapter;
+import com.bignerdranch.expandablerecyclerview.Model.ParentListItem;
+
+import java.lang.ref.WeakReference;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import de.kuschku.libquassel.localtypes.buffers.Buffer;
+import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewConfig;
+import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
+import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
+import de.kuschku.util.observables.callbacks.ElementCallback;
+import de.kuschku.util.observables.callbacks.UICallback;
+import de.kuschku.util.observables.lists.ObservableSortedList;
+
+public class BufferViewConfigAdapter extends ExpandableRecyclerAdapter<NetworkViewHolder, BufferViewHolder> implements OnBufferClickListener {
+    private final AppContext context;
+    private final ObservableSortedList<NetworkItem> items;
+    private final Map<QNetwork, NetworkItem> itemMap = new WeakHashMap<>();
+    private final Map<Integer, BufferViewHolder> bufferViewHolderMap = new WeakHashMap<>();
+    private QBufferViewConfig config;
+    private WeakReference<RecyclerView> recyclerView = new WeakReference<>(null);
+    private int selectedFrom;
+    private int selectedTo;
+    private int open;
+    private OnBufferClickListener bufferClickListener;
+
+    private ElementCallback<QNetwork> callback = new ElementCallback<QNetwork>() {
+        @Override
+        public void notifyItemInserted(QNetwork network) {
+            NetworkItem networkItem = new NetworkItem(context, config, network);
+            itemMap.put(network, networkItem);
+            items.add(networkItem);
+        }
+
+        @Override
+        public void notifyItemRemoved(QNetwork network) {
+            items.remove(itemMap.remove(network));
+        }
+
+        @Override
+        public void notifyItemChanged(QNetwork network) {
+            items.notifyItemChanged(items.indexOf(itemMap.get(network)));
+        }
+    };
+
+    private BufferViewConfigAdapter(AppContext context, ObservableSortedList<NetworkItem> items) {
+        super(items);
+        this.context = context;
+        this.items = items;
+        items.addCallback(new UICallback() {
+            @Override
+            public void notifyItemInserted(int position) {
+                notifyParentItemInserted(position);
+            }
+
+            @Override
+            public void notifyItemChanged(int position) {
+                notifyParentItemChanged(position);
+            }
+
+            @Override
+            public void notifyItemRemoved(int position) {
+                notifyParentItemRemoved(position);
+            }
+
+            @Override
+            public void notifyItemMoved(int from, int to) {
+                notifyParentItemRemoved(from);
+                notifyParentItemInserted(to);
+            }
+
+            @Override
+            public void notifyItemRangeInserted(int position, int count) {
+                notifyParentItemRangeInserted(position, count);
+            }
+
+            @Override
+            public void notifyItemRangeChanged(int position, int count) {
+                for (int i = position; i < position + count; i++) {
+                    notifyParentItemChanged(i);
+                }
+            }
+
+            @Override
+            public void notifyItemRangeRemoved(int position, int count) {
+                for (int i = position; i < position + count; i++) {
+                    notifyParentItemRemoved(position);
+                }
+            }
+        });
+    }
+
+    public static BufferViewConfigAdapter of(AppContext context) {
+        final ObservableSortedList<NetworkItem> networkItems = new ObservableSortedList<>(NetworkItem.class, new ObservableSortedList.ItemComparator<NetworkItem>() {
+            @Override
+            public int compare(NetworkItem o1, NetworkItem o2) {
+                return o1.getNetwork().networkName().compareTo(o2.getNetwork().networkName());
+            }
+
+            @Override
+            public boolean areContentsTheSame(NetworkItem oldItem, NetworkItem newItem) {
+                return oldItem == newItem;
+            }
+
+            @Override
+            public boolean areItemsTheSame(NetworkItem item1, NetworkItem item2) {
+                return item1.getNetwork().networkId() == item2.getNetwork().networkId();
+            }
+        });
+        return new BufferViewConfigAdapter(context, networkItems);
+    }
+
+    @Override
+    public NetworkViewHolder onCreateParentViewHolder(ViewGroup parentViewGroup) {
+        LayoutInflater inflater = LayoutInflater.from(parentViewGroup.getContext());
+        return new NetworkViewHolder(inflater.inflate(NetworkViewHolder.layout(), parentViewGroup, false));
+    }
+
+    @Override
+    public BufferViewHolder onCreateChildViewHolder(ViewGroup childViewGroup) {
+        LayoutInflater inflater = LayoutInflater.from(childViewGroup.getContext());
+        return new BufferViewHolder(context, inflater.inflate(BufferViewHolder.layout(), childViewGroup, false));
+    }
+
+    @Override
+    public void onBindParentViewHolder(NetworkViewHolder parentViewHolder, int position, ParentListItem parentListItem) {
+        parentViewHolder.bind(context, (NetworkItem) parentListItem);
+    }
+
+    @Override
+    public void onBindChildViewHolder(BufferViewHolder childViewHolder, int position, Object childListItem) {
+        bufferViewHolderMap.remove(childViewHolder.id);
+        childViewHolder.bind(this, (Buffer) childListItem);
+        bufferViewHolderMap.put(childViewHolder.id, childViewHolder);
+    }
+
+    @Override
+    public void onClick(Buffer buffer) {
+        if (bufferClickListener != null) {
+            bufferClickListener.onClick(buffer);
+        }
+    }
+
+    public void setBufferClickListener(OnBufferClickListener bufferClickListener) {
+        this.bufferClickListener = bufferClickListener;
+    }
+
+    public void setRecyclerView(RecyclerView recyclerView) {
+        this.recyclerView = new WeakReference<>(recyclerView);
+    }
+
+    public void selectConfig(int id) {
+        QBufferViewConfig newconfig = context.client().bufferViewManager().bufferViewConfig(id);
+        int firstVisible = -1;
+        if (newconfig == config) {
+            RecyclerView list = recyclerView.get();
+            if (list != null) {
+                LinearLayoutManager layoutManager = (LinearLayoutManager) list.getLayoutManager();
+                firstVisible = layoutManager.findFirstVisibleItemPosition();
+            }
+        }
+
+        if (config != null)
+            config.networkList().removeCallback(callback);
+        config = newconfig;
+        config.updateNetworks();
+        items.clear();
+        itemMap.clear();
+        for (QNetwork network : config.networkList()) {
+            NetworkItem networkItem = new NetworkItem(context, config, network);
+            itemMap.put(network, networkItem);
+            items.add(networkItem);
+        }
+        config.networkList().addCallback(callback);
+        if (firstVisible != -1) {
+            RecyclerView list = recyclerView.get();
+            if (list != null) {
+                LinearLayoutManager layoutManager = (LinearLayoutManager) list.getLayoutManager();
+                layoutManager.scrollToPosition(firstVisible);
+            }
+        }
+    }
+
+    public void setSelection(int from, int to) {
+
+    }
+
+    public void setOpen(int id) {
+        BufferViewHolder old = bufferViewHolderMap.get(open);
+        if (old != null) old.setSelected(false);
+        else bufferViewHolderMap.remove(open);
+        BufferViewHolder now = bufferViewHolderMap.get(id);
+        if (now != null) now.setSelected(true);
+        else bufferViewHolderMap.remove(id);
+        open = id;
+    }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigItem.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigItem.java
deleted file mode 100644
index ba724a1de..000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigItem.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * QuasselDroid - Quassel client for Android
- * Copyright (C) 2016 Janne Koschinski
- * Copyright (C) 2016 Ken Børge Viktil
- * Copyright (C) 2016 Magnus Fjell
- * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.kuschku.quasseldroid_ng.ui.chat.drawer;
-
-import android.support.annotation.NonNull;
-
-import com.mikepenz.materialdrawer.Drawer;
-import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import de.kuschku.libquassel.client.Client;
-import de.kuschku.libquassel.client.NetworkManager;
-import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewConfig;
-import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
-import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
-import de.kuschku.util.observables.callbacks.DrawerItemCallback;
-import de.kuschku.util.observables.callbacks.GeneralCallback;
-import de.kuschku.util.observables.callbacks.wrappers.AdapterUICallbackWrapper;
-import de.kuschku.util.observables.lists.ObservableComparableSortedList;
-
-import static de.kuschku.util.AndroidAssert.assertNotNull;
-
-public class BufferViewConfigItem implements DrawerItemCallback {
-    @NonNull
-    private final BufferItemManager manager;
-    @NonNull
-    private final ObservableComparableSortedList<NetworkItem> networks = new ObservableComparableSortedList<>(NetworkItem.class);
-    @NonNull
-    private final Drawer drawer;
-    @NonNull
-    private final QBufferViewConfig config;
-    @NonNull
-    private final AppContext context;
-
-    GeneralCallback rebuildNetworkList = this::rebuildNetworkList;
-    AdapterUICallbackWrapper callbackWrapper;
-
-    public BufferViewConfigItem(@NonNull Drawer drawer, @NonNull QBufferViewConfig config, @NonNull AppContext context) {
-        this.drawer = drawer;
-        this.config = config;
-        this.context = context;
-        manager = new BufferItemManager(context);
-        config.addObserver(rebuildNetworkList);
-        assertNotNull(drawer.getItemAdapter());
-        callbackWrapper = new AdapterUICallbackWrapper(drawer.getItemAdapter());
-        networks.addCallback(callbackWrapper);
-        rebuildNetworkList();
-    }
-
-    private void rebuildNetworkList() {
-        Client client = context.client();
-        assertNotNull(client);
-        NetworkManager networkManager = client.networkManager();
-        assertNotNull(networkManager);
-
-        // First we build a list of all network ids we want to display
-        Set<Integer> ids = new HashSet<>();
-        for (QNetwork network : networkManager.networks()) {
-            if (config.networkId() <= 0 || network.networkId() == config.networkId()) {
-                ids.add(network.networkId());
-            }
-        }
-        // Now we build a list of all items to remove
-        Set<NetworkItem> removed = new HashSet<>();
-        for (NetworkItem item : networks) {
-            if (item.getNetwork() != null && ids.contains(item.getNetwork().networkId())) {
-                // And make sure that ids only contains those networks added
-                ids.remove(item.getNetwork().networkId());
-            } else {
-                removed.add(item);
-                item.removeCallback(this);
-            }
-        }
-
-        // By now we know that removed contains all removed networks, and ids all added ones
-        // We do this to avoid concurrent modification and to reduce the amount of UI changes
-        networks.removeAll(removed);
-        for (IDrawerItem item : removed) {
-            drawer.removeItem(item.getIdentifier());
-        }
-        for (int id : ids) {
-            QNetwork network = networkManager.network(id);
-            if (network != null) {
-                NetworkItem item = new NetworkItem(config, client, manager, network);
-                networks.add(item);
-                item.addCallback(this);
-            }
-        }
-        for (NetworkItem item : networks) {
-            if (ids.contains(item.getNetwork().networkId())) {
-                int position = networks.indexOf(item);
-                drawer.getItemAdapter().add(position, item);
-            }
-        }
-        for (int i = 0; i < drawer.getAdapter().getItemCount(); i++) {
-            IDrawerItem adapterItem = drawer.getAdapter().getItem(i);
-            if (adapterItem instanceof NetworkItem &&
-                    ((NetworkItem) adapterItem).getNetwork().isConnected() &&
-                    ids.contains(((NetworkItem) adapterItem).getNetwork().networkId()))
-                drawer.getAdapter().expand(i);
-        }
-    }
-
-    @Override
-    public void notifyChanged(@NonNull IDrawerItem item) {
-        int position = drawer.getAdapter().getPosition(item);
-        if (position != -1) {
-            drawer.getAdapter().notifyAdapterItemChanged(position);
-            if (item instanceof NetworkItem)
-                drawer.getAdapter().notifyAdapterSubItemsChanged(position);
-        }
-    }
-
-    public void remove() {
-        config.deleteObserver(rebuildNetworkList);
-        networks.removeCallback(callbackWrapper);
-    }
-}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewHolder.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewHolder.java
new file mode 100644
index 000000000..b2179c9b6
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewHolder.java
@@ -0,0 +1,165 @@
+/*
+ * QuasselDroid - Quassel client for Android
+ * Copyright (C) 2016 Janne Koschinski
+ * Copyright (C) 2016 Ken Børge Viktil
+ * Copyright (C) 2016 Magnus Fjell
+ * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid_ng.ui.chat.drawer;
+
+import android.databinding.Observable;
+import android.databinding.ObservableField;
+import android.graphics.drawable.StateListDrawable;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.bignerdranch.expandablerecyclerview.ViewHolder.ChildViewHolder;
+import com.mikepenz.materialize.util.UIUtils;
+
+import java.util.Locale;
+
+import butterknife.Bind;
+import butterknife.ButterKnife;
+import de.kuschku.libquassel.events.BufferChangeEvent;
+import de.kuschku.libquassel.localtypes.buffers.Buffer;
+import de.kuschku.libquassel.localtypes.buffers.ChannelBuffer;
+import de.kuschku.libquassel.localtypes.buffers.QueryBuffer;
+import de.kuschku.libquassel.primitives.types.BufferInfo;
+import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel;
+import de.kuschku.libquassel.syncables.types.interfaces.QIrcUser;
+import de.kuschku.quasseldroid_ng.R;
+import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
+
+public class BufferViewHolder extends ChildViewHolder {
+
+    public int id;
+    @Bind(R.id.material_drawer_icon)
+    ImageView icon;
+    @Bind(R.id.material_drawer_badge)
+    TextView badge;
+    @Bind(R.id.material_drawer_badge_container)
+    LinearLayout badgeContainer;
+    @Bind(R.id.material_drawer_name)
+    TextView name;
+    @Bind(R.id.material_drawer_description)
+    TextView description;
+    private ObservableField<BufferInfo.BufferStatus> status;
+    private Observable.OnPropertyChangedCallback callback;
+    private AppContext context;
+
+    private StateListDrawable background;
+
+    public BufferViewHolder(AppContext context, View itemView) {
+        super(itemView);
+        ButterKnife.bind(this, itemView);
+        this.context = context;
+        context.provider().event.registerSticky(this);
+
+        background = new StateListDrawable();
+        background.addState(new int[]{android.R.attr.state_selected}, itemView.getResources().getDrawable(com.mikepenz.materialdrawer.R.color.material_drawer_selected));
+        background.addState(new int[0], UIUtils.getSelectableBackground(itemView.getContext()));
+    }
+
+    @LayoutRes
+    public static int layout() {
+        return R.layout.widget_buffer;
+    }
+
+    public void bind(OnBufferClickListener listener, Buffer buffer) {
+        if (status != null)
+            status.removeOnPropertyChangedCallback(callback);
+        status = buffer.getStatus();
+        name.setText(buffer.getName());
+        setDescription(context.deserializer().formatString(getDescription(buffer)));
+        setBadge(0);
+        itemView.setOnClickListener(v -> listener.onClick(buffer));
+
+        itemView.setBackground(background);
+
+        id = buffer.getInfo().id();
+
+        BufferInfo.Type type = buffer.getInfo().type();
+        setIcon(context, type, status);
+        callback = new Observable.OnPropertyChangedCallback() {
+            @Override
+            public void onPropertyChanged(Observable sender, int propertyId) {
+                setIcon(context, type, status);
+            }
+        };
+        status.addOnPropertyChangedCallback(callback);
+
+        setSelected();
+    }
+
+    private void setSelected() {
+        setSelected(context.client().backlogManager().open() == id);
+    }
+
+    public void setSelected(boolean selected) {
+        itemView.setSelected(selected);
+    }
+
+    private void setIcon(AppContext context, BufferInfo.Type type, ObservableField<BufferInfo.BufferStatus> status) {
+        icon.setImageDrawable(context.themeUtil().statusDrawables.of(type, status.get()));
+    }
+
+    private void setDescription(@Nullable CharSequence description) {
+        if (description == null || description.length() == 0) {
+            this.description.setText(null);
+            this.description.setVisibility(View.GONE);
+        } else {
+            this.description.setText(description);
+            this.description.setVisibility(View.VISIBLE);
+        }
+    }
+
+    private void setBadge(int count) {
+        if (count == 0) {
+            badgeContainer.setVisibility(View.GONE);
+            badge.setText("0");
+        } else {
+            badgeContainer.setVisibility(View.VISIBLE);
+            badge.setText(String.format(Locale.US, "%d", count));
+        }
+    }
+
+    @Nullable
+    private String getDescription(Buffer buffer) {
+        if (buffer instanceof ChannelBuffer) {
+            ChannelBuffer channelBuffer = (ChannelBuffer) buffer;
+            QIrcChannel channel = channelBuffer.getChannel();
+            if (channel != null) {
+                return channel.topic();
+            }
+        } else if (buffer instanceof QueryBuffer) {
+            QueryBuffer queryBuffer = (QueryBuffer) buffer;
+            QIrcUser user = queryBuffer.getUser();
+            if (user != null) {
+                return user.realName();
+            }
+        }
+        return null;
+    }
+
+    public void onEventMainThread(BufferChangeEvent event) {
+        setSelected();
+    }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NetworkItem.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NetworkItem.java
index 9a21ffcfc..3b989be83 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NetworkItem.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NetworkItem.java
@@ -21,108 +21,92 @@
 
 package de.kuschku.quasseldroid_ng.ui.chat.drawer;
 
-import android.support.annotation.NonNull;
+import com.bignerdranch.expandablerecyclerview.Model.ParentListItem;
 
-import com.mikepenz.materialdrawer.holder.StringHolder;
-import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
-import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
-
-import java.util.ArrayList;
 import java.util.List;
 
-import de.kuschku.libquassel.client.Client;
+import de.kuschku.libquassel.localtypes.buffers.Buffer;
+import de.kuschku.libquassel.primitives.types.BufferInfo;
 import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewConfig;
 import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
-import de.kuschku.util.observables.ContentComparable;
-import de.kuschku.util.observables.IObservable;
-import de.kuschku.util.observables.callbacks.DrawerItemCallback;
+import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
+import de.kuschku.util.irc.IrcCaseMapper;
 import de.kuschku.util.observables.callbacks.ElementCallback;
-import de.kuschku.util.observables.callbacks.wrappers.MultiDrawerItemCallback;
+import de.kuschku.util.observables.lists.ObservableSortedList;
 
-public class NetworkItem extends PrimaryDrawerItem implements IObservable<DrawerItemCallback>, ContentComparable<NetworkItem> {
-    @NonNull
-    private final QBufferViewConfig config;
-    @NonNull
-    private final Client client;
-    @NonNull
-    private final BufferItemManager manager;
-    @NonNull
+public class NetworkItem implements ParentListItem {
     private final QNetwork network;
-    private final MultiDrawerItemCallback callback = MultiDrawerItemCallback.of();
+    private final ObservableSortedList<Buffer> buffers = new ObservableSortedList<>(Buffer.class, new ObservableSortedList.ItemComparator<Buffer>() {
+        @Override
+        public int compare(Buffer o1, Buffer o2) {
+            if (o1.getInfo().type() == o2.getInfo().type()) {
+                return IrcCaseMapper.toLowerCase(o1.getName()).compareTo(IrcCaseMapper.toLowerCase(o2.getName()));
+            } else {
+                if (o1.getInfo().type() == BufferInfo.Type.STATUS)
+                    return -1;
+                else if (o2.getInfo().type() == BufferInfo.Type.STATUS)
+                    return 1;
+                else if (o1.getInfo().type() == BufferInfo.Type.CHANNEL)
+                    return -1;
+                else if (o2.getInfo().type() == BufferInfo.Type.CHANNEL)
+                    return 1;
+                else if (o1.getInfo().type() == BufferInfo.Type.GROUP)
+                    return -1;
+                else if (o2.getInfo().type() == BufferInfo.Type.GROUP)
+                    return 1;
+                else
+                    return -1;
+            }
+        }
+
+        @Override
+        public boolean areContentsTheSame(Buffer oldItem, Buffer newItem) {
+            return oldItem == newItem;
+        }
+
+        @Override
+        public boolean areItemsTheSame(Buffer item1, Buffer item2) {
+            return item1.getInfo().id() == item2.getInfo().id();
+        }
+    });
 
-    public NetworkItem(@NonNull QBufferViewConfig config, @NonNull Client client, @NonNull BufferItemManager manager, @NonNull QNetwork network) {
-        this.config = config;
-        this.client = client;
-        this.manager = manager;
+    public NetworkItem(AppContext context, QBufferViewConfig config, QNetwork network) {
         this.network = network;
-        ElementCallback<Integer> elemCallback = new ElementCallback<Integer>() {
+        for (int id : config.bufferList()) {
+            Buffer buffer = context.client().bufferManager().buffer(id);
+            if (buffer != null && buffer.getInfo().networkId() == network.networkId())
+                buffers.add(buffer);
+        }
+        config.bufferIds().addCallback(new ElementCallback<Integer>() {
             @Override
-            public void notifyItemInserted(Integer element) {
-                callback.notifyChanged(NetworkItem.this);
+            public void notifyItemInserted(Integer id) {
+                Buffer buffer = context.client().bufferManager().buffer(id);
+                if (buffer != null && buffer.getInfo().networkId() == network.networkId())
+                    buffers.add(buffer);
             }
 
             @Override
-            public void notifyItemRemoved(Integer element) {
-                callback.notifyChanged(NetworkItem.this);
+            public void notifyItemRemoved(Integer id) {
+                buffers.remove(context.client().bufferManager().buffer(id));
             }
 
             @Override
-            public void notifyItemChanged(Integer element) {
-                callback.notifyChanged(manager.get(element));
-            }
-        };
-        config.bufferIds().addCallback(elemCallback);
-        client.bufferManager().byNetwork(network.networkId()).addCallback(elemCallback);
-    }
-
-    @NonNull
-    @Override
-    public List<IDrawerItem> getSubItems() {
-        List<IDrawerItem> bufferItems = new ArrayList<>();
-        for (int id : config.bufferList()) {
-            if (client.bufferManager().byNetwork(network.networkId()).contains(id)) {
-                if (config.allowedBufferTypes() == 0 ||
-                        config.allowedBufferTypes() == -1 ||
-                        (config.allowedBufferTypes() & client.bufferManager().buffer(id).getInfo().type().id) != 0)
-
-                    bufferItems.add(manager.get(id));
+            public void notifyItemChanged(Integer id) {
+                buffers.notifyItemChanged(buffers.indexOf(context.client().bufferManager().buffer(id)));
             }
-        }
-        return bufferItems;
+        });
     }
 
-    @NonNull
     @Override
-    public StringHolder getName() {
-        return new StringHolder(network.networkName());
+    public List<?> getChildItemList() {
+        return buffers;
     }
 
     @Override
-    public void addCallback(DrawerItemCallback callback) {
-        this.callback.addCallback(callback);
+    public boolean isInitiallyExpanded() {
+        return network.isConnected();
     }
 
-    @Override
-    public void removeCallback(DrawerItemCallback callback) {
-        this.callback.removeCallback(callback);
-    }
-
-    @Override
-    public boolean areItemsTheSame(@NonNull NetworkItem other) {
-        return network.networkId() == other.network.networkId();
-    }
-
-    @Override
-    public boolean areContentsTheSame(NetworkItem other) {
-        return network.equals(other);
-    }
-
-    @Override
-    public int compareTo(@NonNull NetworkItem another) {
-        return network.networkName().compareToIgnoreCase(another.network.networkName());
-    }
-
-    @NonNull
     public QNetwork getNetwork() {
         return network;
     }
@@ -131,9 +115,4 @@ public class NetworkItem extends PrimaryDrawerItem implements IObservable<Drawer
     public String toString() {
         return String.valueOf(network);
     }
-
-    @Override
-    public long getIdentifier() {
-        return network.networkId() << 16;
-    }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ILayoutHelper.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NetworkViewHolder.java
similarity index 51%
rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ILayoutHelper.java
rename to app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NetworkViewHolder.java
index feb431580..3151de82b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ILayoutHelper.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NetworkViewHolder.java
@@ -19,15 +19,35 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid_ng.ui.chat.util;
+package de.kuschku.quasseldroid_ng.ui.chat.drawer;
 
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.Toolbar;
+import android.support.annotation.LayoutRes;
+import android.view.View;
+import android.widget.TextView;
 
-import com.mikepenz.materialdrawer.AccountHeader;
-import com.mikepenz.materialdrawer.Drawer;
+import com.bignerdranch.expandablerecyclerview.ViewHolder.ParentViewHolder;
 
-public interface ILayoutHelper {
-    Drawer buildDrawer(@Nullable Bundle savedInstanceState, AccountHeader accountHeader, Toolbar toolbar);
+import butterknife.Bind;
+import butterknife.ButterKnife;
+import de.kuschku.quasseldroid_ng.R;
+import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
+
+public class NetworkViewHolder extends ParentViewHolder {
+
+    @Bind(R.id.material_drawer_name)
+    TextView name;
+
+    public NetworkViewHolder(View itemView) {
+        super(itemView);
+        ButterKnife.bind(this, itemView);
+    }
+
+    @LayoutRes
+    public static int layout() {
+        return R.layout.widget_network;
+    }
+
+    public void bind(AppContext context, NetworkItem item) {
+        name.setText(item.getNetwork().networkName());
+    }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NickListWrapper.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NickListWrapper.java
deleted file mode 100644
index 0e55bf39a..000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/NickListWrapper.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * QuasselDroid - Quassel client for Android
- * Copyright (C) 2016 Janne Koschinski
- * Copyright (C) 2016 Ken Børge Viktil
- * Copyright (C) 2016 Magnus Fjell
- * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.kuschku.quasseldroid_ng.ui.chat.drawer;
-
-import android.support.annotation.NonNull;
-
-import com.mikepenz.materialdrawer.Drawer;
-import com.mikepenz.materialdrawer.holder.BadgeStyle;
-import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
-import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
-
-import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel;
-import de.kuschku.libquassel.syncables.types.interfaces.QIrcUser;
-import de.kuschku.util.backports.Objects;
-import de.kuschku.util.irc.IrcCaseMapper;
-import de.kuschku.util.observables.callbacks.ElementCallback;
-import de.kuschku.util.observables.callbacks.UICallback;
-import de.kuschku.util.observables.lists.ObservableSortedList;
-
-public class NickListWrapper {
-    @NonNull
-    private final QIrcChannel channel;
-    private final ObservableSortedList<QIrcUser> list = new ObservableSortedList<>(QIrcUser.class, new ObservableSortedList.ItemComparator<QIrcUser>() {
-        @Override
-        public int compare(@NonNull QIrcUser o1, @NonNull QIrcUser o2) {
-            int indexa = channel.network().modeToIndex(channel.userModes(o1));
-            int indexb = channel.network().modeToIndex(channel.userModes(o2));
-            if (indexa == indexb) {
-                return o1.nick().compareToIgnoreCase(o2.nick());
-            } else {
-                return indexa - indexb;
-            }
-        }
-
-        @Override
-        public boolean areContentsTheSame(QIrcUser oldItem, QIrcUser newItem) {
-            return oldItem == newItem;
-        }
-
-        @Override
-        public boolean areItemsTheSame(@NonNull QIrcUser item1, @NonNull QIrcUser item2) {
-            return Objects.equals(item1.hostmask(), item2.hostmask());
-        }
-    });
-
-    public NickListWrapper(@NonNull Drawer drawerRight, @NonNull QIrcChannel channel) {
-        drawerRight.removeAllItems();
-        this.channel = channel;
-        for (String nick : channel.users()) {
-            list.add(channel.network().ircUser(nick));
-        }
-        channel.users().addCallback(new ElementCallback<String>() {
-            @Override
-            public void notifyItemInserted(String element) {
-                list.add(channel.network().ircUser(element));
-            }
-
-            @Override
-            public void notifyItemRemoved(String element) {
-                for (QIrcUser user : list) {
-                    if (IrcCaseMapper.equalsIgnoreCase(user.nick(), element)) {
-                        list.remove(user);
-                        return;
-                    }
-                }
-            }
-
-            @Override
-            public void notifyItemChanged(String element) {
-                for (int i = 0; i < list.size(); i++) {
-                    if (IrcCaseMapper.equalsIgnoreCase(list.get(i).nick(), element)) {
-                        list.notifyItemChanged(i);
-                        return;
-                    }
-                }
-            }
-        });
-        this.list.addCallback(new UICallback() {
-            @Override
-            public void notifyItemInserted(int position) {
-                drawerRight.getItemAdapter().add(position, fromUser(list.get(position)));
-            }
-
-            @Override
-            public void notifyItemChanged(int position) {
-                drawerRight.getItemAdapter().notifyItemChanged(position);
-            }
-
-            @Override
-            public void notifyItemRemoved(int position) {
-                drawerRight.removeItemByPosition(position);
-            }
-
-            @Override
-            public void notifyItemMoved(int from, int to) {
-                notifyItemRemoved(from);
-                notifyItemInserted(from);
-            }
-
-            @Override
-            public void notifyItemRangeInserted(int position, int count) {
-                for (int i = position; i < position + count; i++) {
-                    notifyItemInserted(i);
-                }
-            }
-
-            @Override
-            public void notifyItemRangeChanged(int position, int count) {
-                for (int i = position; i < position + count; i++) {
-                    notifyItemChanged(i);
-                }
-            }
-
-            @Override
-            public void notifyItemRangeRemoved(int position, int count) {
-                for (int i = position; i < position + count; i++) {
-                    notifyItemRemoved(i);
-                }
-            }
-        });
-        for (QIrcUser user : list) {
-            if (user != null)
-                drawerRight.getItemAdapter().add(fromUser(user));
-        }
-    }
-
-    private IDrawerItem fromUser(@NonNull QIrcUser user) {
-        return new PrimaryDrawerItem()
-                .withName(user.nick())
-                .withBadge(channel.network().modeToPrefix(channel.userModes(user)))
-                .withBadgeStyle(new BadgeStyle().withColor(0xFFFF0000).withTextColor(0xFFFFFFFF));
-    }
-}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ActivityImplFactory.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/OnBufferClickListener.java
similarity index 70%
rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ActivityImplFactory.java
rename to app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/OnBufferClickListener.java
index 26e7f29fa..c5d505cf1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ActivityImplFactory.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/OnBufferClickListener.java
@@ -19,17 +19,10 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid_ng.ui.chat.util;
+package de.kuschku.quasseldroid_ng.ui.chat.drawer;
 
-import de.kuschku.quasseldroid_ng.ui.chat.MainActivity;
+import de.kuschku.libquassel.localtypes.buffers.Buffer;
 
-public class ActivityImplFactory {
-    private ActivityImplFactory() {
-
-    }
-
-
-    public static ILayoutHelper of(boolean tablet, MainActivity activity) {
-        return (tablet) ? new LayoutHelperTabletImpl(activity) : new LayoutHelperPhoneImpl(activity);
-    }
+public interface OnBufferClickListener {
+    void onClick(Buffer buffer);
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperPhoneImpl.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperPhoneImpl.java
deleted file mode 100644
index a8b777570..000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperPhoneImpl.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * QuasselDroid - Quassel client for Android
- * Copyright (C) 2016 Janne Koschinski
- * Copyright (C) 2016 Ken Børge Viktil
- * Copyright (C) 2016 Magnus Fjell
- * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.kuschku.quasseldroid_ng.ui.chat.util;
-
-import android.os.Bundle;
-import android.support.v7.widget.Toolbar;
-
-import com.mikepenz.materialdrawer.AccountHeader;
-import com.mikepenz.materialdrawer.Drawer;
-import com.mikepenz.materialdrawer.DrawerBuilder;
-
-import de.kuschku.quasseldroid_ng.ui.chat.MainActivity;
-
-public class LayoutHelperPhoneImpl implements ILayoutHelper {
-    private final MainActivity activity;
-
-    public LayoutHelperPhoneImpl(MainActivity activity) {
-        this.activity = activity;
-    }
-
-    @Override
-    public Drawer buildDrawer(Bundle savedInstanceState, AccountHeader accountHeader, Toolbar toolbar) {
-        return new DrawerBuilder()
-                .withActivity(activity)
-                .withToolbar(toolbar)
-                .withAccountHeader(accountHeader)
-                .withTranslucentStatusBar(true)
-                .withSavedInstance(savedInstanceState)
-                .build();
-    }
-}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperTabletImpl.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperTabletImpl.java
deleted file mode 100644
index 3ced622bc..000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/LayoutHelperTabletImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * QuasselDroid - Quassel client for Android
- * Copyright (C) 2016 Janne Koschinski
- * Copyright (C) 2016 Ken Børge Viktil
- * Copyright (C) 2016 Magnus Fjell
- * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.kuschku.quasseldroid_ng.ui.chat.util;
-
-import android.os.Bundle;
-import android.support.v7.widget.Toolbar;
-import android.widget.FrameLayout;
-
-import com.mikepenz.materialdrawer.AccountHeader;
-import com.mikepenz.materialdrawer.Drawer;
-import com.mikepenz.materialdrawer.DrawerBuilder;
-
-import de.kuschku.quasseldroid_ng.R;
-import de.kuschku.quasseldroid_ng.ui.chat.MainActivity;
-
-public class LayoutHelperTabletImpl implements ILayoutHelper {
-    private final MainActivity activity;
-
-    public LayoutHelperTabletImpl(MainActivity activity) {
-        this.activity = activity;
-    }
-
-    @Override
-    public Drawer buildDrawer(Bundle savedInstanceState, AccountHeader accountHeader, Toolbar toolbar) {
-        Drawer drawer = new DrawerBuilder()
-                .withActivity(activity)
-                .withToolbar(toolbar)
-                .withAccountHeader(accountHeader)
-                .withTranslucentStatusBar(false)
-                .withSavedInstance(savedInstanceState)
-                .buildView();
-        FrameLayout drawerHost = (FrameLayout) activity.findViewById(R.id.drawer_host);
-        drawerHost.addView(drawer.getSlider());
-        return drawer;
-    }
-}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java
index c847f05c6..759bf7441 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/theme/ThemeUtil.java
@@ -22,13 +22,16 @@
 package de.kuschku.quasseldroid_ng.ui.theme;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
+import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v7.view.ContextThemeWrapper;
 
 import de.kuschku.libquassel.events.ConnectionChangeEvent;
+import de.kuschku.libquassel.primitives.types.BufferInfo;
 import de.kuschku.quasseldroid_ng.R;
 import de.kuschku.util.annotationbind.AutoBinder;
 import de.kuschku.util.annotationbind.AutoColor;
@@ -45,14 +48,18 @@ public class ThemeUtil {
     public final FormatStrings translations = new FormatStrings();
     @NonNull
     public final DateTimeFormatHelper formatter;
+    @NonNull
+    public final StatusDrawables statusDrawables;
 
     public ThemeUtil(@NonNull Context ctx) {
         initColors(new ContextThemeWrapper(ctx, ctx.getTheme()));
+        statusDrawables = new StatusDrawables(ctx, res);
         formatter = new DateTimeFormatHelper(ctx);
     }
 
     public ThemeUtil(@NonNull Context ctx, @NonNull AppTheme theme) {
         initColors(new ContextThemeWrapper(ctx, theme.themeId));
+        statusDrawables = new StatusDrawables(ctx, res);
         formatter = new DateTimeFormatHelper(ctx);
     }
 
@@ -82,6 +89,42 @@ public class ThemeUtil {
         }
     }
 
+    public static class StatusDrawables {
+        public final Drawable online;
+        public final Drawable away;
+        public final Drawable offline;
+
+        public final Drawable channelOnline;
+        public final Drawable channelOffline;
+
+        public StatusDrawables(Context ctx, Colors colors) {
+            online = ctx.getResources().getDrawable(R.drawable.ic_status);
+            DrawableCompat.setTint(online, colors.colorAccent);
+            away = ctx.getResources().getDrawable(R.drawable.ic_status);
+            offline = ctx.getResources().getDrawable(R.drawable.ic_status_offline);
+
+            channelOnline = ctx.getResources().getDrawable(R.drawable.ic_status_channel);
+            DrawableCompat.setTint(channelOnline, colors.colorAccent);
+            channelOffline = ctx.getResources().getDrawable(R.drawable.ic_status_channel_offline);
+        }
+
+        public Drawable of(BufferInfo.Type type, BufferInfo.BufferStatus status) {
+            if (type == BufferInfo.Type.CHANNEL) {
+                if (status == BufferInfo.BufferStatus.ONLINE)
+                    return channelOnline;
+                else
+                    return channelOffline;
+            } else {
+                if (status == BufferInfo.BufferStatus.ONLINE)
+                    return online;
+                else if (status == BufferInfo.BufferStatus.AWAY)
+                    return away;
+                else
+                    return offline;
+            }
+        }
+    }
+
     public static class FormatStrings {
         @AutoString(R.string.usernameHostmask)
         public String usernameHostmask;
diff --git a/app/src/main/res/drawable/badge.xml b/app/src/main/res/drawable/badge.xml
new file mode 100644
index 000000000..568414bec
--- /dev/null
+++ b/app/src/main/res/drawable/badge.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ QuasselDroid - Quassel client for Android
+  ~ Copyright (C) 2016 Janne Koschinski
+  ~ Copyright (C) 2016 Ken Børge Viktil
+  ~ Copyright (C) 2016 Magnus Fjell
+  ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify it
+  ~ under the terms of the GNU General Public License as published by the Free
+  ~ Software Foundation, either version 3 of the License, or (at your option)
+  ~ any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License along
+  ~ with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/md_red_500" />
+    <padding
+        android:bottom="10dp"
+        android:left="10dp"
+        android:right="10dp"
+        android:top="10dp" />
+    <corners android:radius="6dp" />
+</shape>
diff --git a/app/src/main/res/layout-w720dp/activity_main.xml b/app/src/main/res/layout-w720dp/activity_main.xml
index 2193aacb6..5f40523c2 100644
--- a/app/src/main/res/layout-w720dp/activity_main.xml
+++ b/app/src/main/res/layout-w720dp/activity_main.xml
@@ -22,17 +22,48 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:orientation="horizontal"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="?attr/colorBackground"
+    android:orientation="horizontal"
     tools:context=".ui.chat.MainActivity">
 
-    <FrameLayout
-        android:id="@+id/drawer_host"
+    <LinearLayout
         android:layout_width="300dp"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            xmlns:app="http://schemas.android.com/apk/res-auto"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:theme="@style/AppTheme.AppBarOverlay">
+
+            <android.support.v7.widget.Toolbar
+                android:id="@+id/chatListToolbar"
+                android:layout_width="match_parent"
+                android:layout_height="?attr/actionBarSize"
+                android:background="?attr/colorPrimary"
+                android:theme="@style/AppTheme.AppBarOverlay"
+                app:popupTheme="@style/AppTheme.PopupOverlay">
+
+                <android.support.v7.widget.AppCompatSpinner
+                    android:id="@+id/chatListSpinner"
+                    android:layout_width="fill_parent"
+                    android:layout_height="match_parent" />
+
+            </android.support.v7.widget.Toolbar>
+
+        </android.support.design.widget.AppBarLayout>
+
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/chatList"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </LinearLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -47,4 +78,5 @@
             android:layout_height="match_parent" />
 
     </LinearLayout>
+
 </LinearLayout>
diff --git a/app/src/main/res/layout/activity_channel_detail.xml b/app/src/main/res/layout/activity_channel_detail.xml
index ba7bba87b..9b08044c7 100644
--- a/app/src/main/res/layout/activity_channel_detail.xml
+++ b/app/src/main/res/layout/activity_channel_detail.xml
@@ -20,7 +20,6 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="?attr/colorBackground"
@@ -52,11 +51,11 @@
                 style="@style/TextAppearance.AppCompat.Button"
                 android:layout_width="match_parent"
                 android:layout_height="48dp"
-                android:textColor="?attr/colorAccent"
-                android:text="Topic"
                 android:layout_marginLeft="16dp"
                 android:layout_marginRight="16dp"
-                android:gravity="fill_vertical" />
+                android:gravity="fill_vertical"
+                android:text="Topic"
+                android:textColor="?attr/colorAccent" />
 
             <TextView
                 android:id="@+id/topic"
@@ -64,20 +63,17 @@
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="16dp"
                 android:layout_marginRight="16dp"
-                android:text="No Topic Set"
-                android:textStyle="italic"
-                android:textColor="?attr/colorForegroundSecondary"
                 android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead" />
 
             <android.support.v7.widget.AppCompatButton
+                android:id="@+id/edit_topic"
+                style="@style/Widget.AppCompat.Button.Colored"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_gravity="right"
                 android:layout_marginLeft="16dp"
                 android:layout_marginRight="16dp"
-                android:id="@+id/edit_topic"
-                android:text="Edit Topic"
-                style="@style/Widget.AppCompat.Button.Colored"
-                android:layout_gravity="right" />
+                android:text="Edit Topic" />
 
             <View
                 android:layout_width="match_parent"
@@ -89,30 +85,30 @@
                 style="@style/TextAppearance.AppCompat.Button"
                 android:layout_width="match_parent"
                 android:layout_height="48dp"
-                android:textColor="?attr/colorAccent"
-                android:text="Channel Modes"
                 android:layout_marginLeft="16dp"
                 android:layout_marginRight="16dp"
-                android:gravity="fill_vertical" />
+                android:gravity="fill_vertical"
+                android:text="Channel Modes"
+                android:textColor="?attr/colorAccent" />
 
             <LinearLayout
                 android:id="@+id/modes"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
+                android:paddingBottom="8dp"
                 android:paddingLeft="8dp"
-                android:paddingRight="8dp"
-                android:paddingBottom="8dp" />
+                android:paddingRight="8dp" />
 
         </LinearLayout>
 
     </ScrollView>
 
     <ProgressBar
+        android:id="@+id/progressBar2"
         style="?android:attr/progressBarStyleLarge"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:id="@+id/progressBar2"
         android:layout_gravity="right" />
 
 </LinearLayout>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 50c6366d1..6d6116907 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -20,19 +20,70 @@
   ~ with this program.  If not, see <http://www.gnu.org/licenses/>.
   -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/drawer_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
+    android:background="?attr/colorBackground"
     tools:context=".ui.chat.MainActivity">
 
-    <include layout="@layout/widget_actionbar" />
-
-    <FrameLayout
-        android:id="@+id/content_host"
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <include layout="@layout/widget_actionbar" />
+
+        <FrameLayout
+            android:id="@+id/content_host"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    </LinearLayout>
+
+    <android.support.design.widget.NavigationView
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:background="?attr/colorBackground">
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+
+            <android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:app="http://schemas.android.com/apk/res-auto"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:theme="@style/AppTheme.AppBarOverlay">
+
+                <android.support.v7.widget.Toolbar
+                    android:id="@+id/chatListToolbar"
+                    android:layout_width="match_parent"
+                    android:layout_height="?attr/actionBarSize"
+                    android:background="?attr/colorPrimary"
+                    android:theme="@style/AppTheme.AppBarOverlay"
+                    app:popupTheme="@style/AppTheme.PopupOverlay">
+
+                    <android.support.v7.widget.AppCompatSpinner
+                        android:id="@+id/chatListSpinner"
+                        android:layout_width="fill_parent"
+                        android:layout_height="match_parent" />
+
+                </android.support.v7.widget.Toolbar>
+
+            </android.support.design.widget.AppBarLayout>
+
+            <android.support.v7.widget.RecyclerView
+                android:id="@+id/chatList"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+        </LinearLayout>
+
+    </android.support.design.widget.NavigationView>
 
-</LinearLayout>
+</android.support.v4.widget.DrawerLayout>
diff --git a/app/src/main/res/layout/fragment_chat.xml b/app/src/main/res/layout/fragment_chat.xml
index a38ddea75..5816e09be 100644
--- a/app/src/main/res/layout/fragment_chat.xml
+++ b/app/src/main/res/layout/fragment_chat.xml
@@ -22,8 +22,8 @@
 
 <com.sothree.slidinguppanel.SlidingUpPanelLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/sliding_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -32,7 +32,6 @@
     app:umanoPanelHeight="?attr/actionBarSize"
     app:umanoScrollableView="@+id/chatline_scroller"
     app:umanoShadowHeight="4dp"
-    android:background="?attr/colorBackground"
     tools:showIn="@layout/activity_chat">
 
     <android.support.v4.widget.SwipeRefreshLayout
diff --git a/app/src/main/res/layout/fragment_loading.xml b/app/src/main/res/layout/fragment_loading.xml
index 0e3d3cafe..17025c0e1 100644
--- a/app/src/main/res/layout/fragment_loading.xml
+++ b/app/src/main/res/layout/fragment_loading.xml
@@ -22,8 +22,7 @@
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="?attr/colorBackground">
+    android:layout_height="match_parent">
 
     <LinearLayout
         android:layout_width="240dp"
diff --git a/app/src/main/res/layout/widget_buffer.xml b/app/src/main/res/layout/widget_buffer.xml
new file mode 100644
index 000000000..11744dd70
--- /dev/null
+++ b/app/src/main/res/layout/widget_buffer.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ QuasselDroid - Quassel client for Android
+  ~ Copyright (C) 2016 Janne Koschinski
+  ~ Copyright (C) 2016 Ken Børge Viktil
+  ~ Copyright (C) 2016 Magnus Fjell
+  ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify it
+  ~ under the terms of the GNU General Public License as published by the Free
+  ~ Software Foundation, either version 3 of the License, or (at your option)
+  ~ any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License along
+  ~ with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/material_drawer_item_secondary"
+    android:clickable="true"
+    android:orientation="horizontal"
+    android:paddingEnd="@dimen/material_drawer_vertical_padding"
+    android:paddingLeft="@dimen/material_drawer_vertical_padding"
+    android:paddingRight="@dimen/material_drawer_vertical_padding"
+    android:paddingStart="@dimen/material_drawer_vertical_padding">
+
+    <ImageView
+        android:id="@+id/material_drawer_icon"
+        android:layout_width="@dimen/material_drawer_item_secondary_icon"
+        android:layout_height="@dimen/material_drawer_item_secondary"
+        android:layout_gravity="center_vertical"
+        android:paddingBottom="@dimen/material_drawer_item_secondary_icon_padding"
+        android:paddingEnd="@dimen/material_drawer_item_secondary_icon_padding_right"
+        android:paddingLeft="0dp"
+        android:paddingRight="@dimen/material_drawer_item_secondary_icon_padding_right"
+        android:paddingStart="0dp"
+        android:paddingTop="@dimen/material_drawer_item_secondary_icon_padding" />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center_vertical|start"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/material_drawer_name"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif-medium"
+            android:gravity="center_vertical|start"
+            android:lines="1"
+            android:singleLine="true"
+            android:textSize="@dimen/material_drawer_item_secondary_text"
+            tools:text="Some secondary text" />
+
+        <TextView
+            android:id="@+id/material_drawer_description"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif"
+            android:gravity="center_vertical|start"
+            android:lines="1"
+            android:singleLine="true"
+            android:textSize="@dimen/material_drawer_item_secondary_description"
+            tools:text="Some drawer text" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/material_drawer_badge_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:background="@drawable/badge"
+        android:gravity="center"
+        android:padding="6dp">
+
+        <TextView
+            android:id="@+id/material_drawer_badge"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:fontFamily="sans-serif"
+            android:gravity="center"
+            android:lines="1"
+            android:minWidth="20dp"
+            android:paddingLeft="1dp"
+            android:paddingRight="1dp"
+            android:singleLine="true"
+            android:textColor="@color/md_white_1000"
+            android:textSize="@dimen/material_drawer_item_secondary_text"
+            tools:text="99+" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_network.xml b/app/src/main/res/layout/widget_network.xml
new file mode 100644
index 000000000..ab5ee3e78
--- /dev/null
+++ b/app/src/main/res/layout/widget_network.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ QuasselDroid - Quassel client for Android
+  ~ Copyright (C) 2016 Janne Koschinski
+  ~ Copyright (C) 2016 Ken Børge Viktil
+  ~ Copyright (C) 2016 Magnus Fjell
+  ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify it
+  ~ under the terms of the GNU General Public License as published by the Free
+  ~ Software Foundation, either version 3 of the License, or (at your option)
+  ~ any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License along
+  ~ with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/material_drawer_item_primary"
+    android:background="?attr/selectableItemBackground"
+    android:clickable="true"
+    android:orientation="horizontal"
+    android:paddingEnd="@dimen/material_drawer_vertical_padding"
+    android:paddingLeft="@dimen/material_drawer_vertical_padding"
+    android:paddingRight="@dimen/material_drawer_vertical_padding"
+    android:paddingStart="@dimen/material_drawer_vertical_padding">
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center_vertical|start"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/material_drawer_name"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif-medium"
+            android:gravity="center_vertical|start"
+            android:lines="1"
+            android:singleLine="true"
+            android:textDirection="anyRtl"
+            android:textSize="@dimen/material_drawer_item_primary_text"
+            tools:text="Some drawer text" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 86cf89e1d..e7d116012 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -73,4 +73,5 @@
     <string name="statusConnected">Connected</string>
     <string name="statusWelcome">Welcome!</string>
     <string name="statusDisconnected">Connection lost</string>
+    <string name="no_topic_set">No Topic Set</string>
 </resources>
-- 
GitLab