From e8b250bf17b15299d92e73559c504d54f538756f Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sun, 7 Feb 2016 19:40:15 +0100
Subject: [PATCH] Rewrote the Drawer handling, should be more efficient and
 less buggy now.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Still existing, known, bugs: adding/removing a buffer doesn’t update the drawer properly until the viewconfig is re-rendered.
---
 app/build.gradle                              |   2 +-
 .../de/kuschku/libquassel/client/AClient.java |   4 +-
 .../libquassel/client/BufferManager.java      |  23 ++
 .../de/kuschku/libquassel/client/Client.java  |  10 +-
 .../libquassel/client/NetworkManager.java     |  17 +-
 .../syncables/types/SyncableObject.java       |   9 +-
 .../syncables/types/impl/AliasManager.java    |   6 +-
 .../syncables/types/impl/BacklogManager.java  |  25 +-
 .../syncables/types/impl/BufferSyncer.java    |   7 +-
 .../types/impl/BufferViewConfig.java          |  29 ++-
 .../types/impl/BufferViewManager.java         |   4 +-
 .../syncables/types/impl/CoreInfo.java        |   4 +-
 .../syncables/types/impl/Identity.java        |   4 +-
 .../types/impl/IgnoreListManager.java         |   6 +-
 .../syncables/types/impl/IrcChannel.java      |   6 +-
 .../syncables/types/impl/IrcUser.java         |   4 +-
 .../syncables/types/impl/Network.java         |  29 ++-
 .../syncables/types/impl/NetworkConfig.java   |   4 +-
 .../syncables/types/impl/NetworkInfo.java     |  63 ++++++
 .../types/interfaces/QAliasManager.java       |   2 +-
 .../types/interfaces/QBacklogManager.java     |   4 +
 .../types/interfaces/QBufferSyncer.java       |   2 +-
 .../types/interfaces/QBufferViewConfig.java   |  11 +-
 .../types/interfaces/QBufferViewManager.java  |   2 +-
 .../types/interfaces/QCertManager.java        |   2 +-
 .../syncables/types/interfaces/QCoreInfo.java |   2 +-
 .../syncables/types/interfaces/QIdentity.java |   2 +-
 .../types/interfaces/QIgnoreListManager.java  |   2 +-
 .../types/interfaces/QIrcChannel.java         |   2 +-
 .../syncables/types/interfaces/QIrcUser.java  |   2 +-
 .../syncables/types/interfaces/QNetwork.java  |   2 +-
 .../types/interfaces/QNetworkConfig.java      |   2 +-
 .../types/interfaces/QObservable.java         |  30 +++
 .../types/interfaces/QSyncableObject.java     |   6 +-
 .../quasseldroid_ng/ui/chat/ChatActivity.java |  19 +-
 .../ui/chat/drawer/BufferItem.java            |  54 +----
 .../ui/chat/drawer/BufferItemManager.java     |  79 +++++++
 .../ui/chat/drawer/BufferViewConfigItem.java  | 112 +++++++++
 .../chat/drawer/BufferViewConfigWrapper.java  | 103 ---------
 .../ui/chat/drawer/NetworkItem.java           | 213 +++++-------------
 .../callbacks/DrawerItemCallback.java         |  28 +++
 .../callbacks/GeneralObservable.java          |  49 ++++
 .../wrappers/MultiDrawerItemCallback.java     |  64 ++++++
 ...Wrapper.java => MultiGeneralCallback.java} |  14 +-
 .../lists/ObservableComparableSortedList.java |   4 +-
 .../observables/lists/ObservableList.java     |   7 +
 .../util/observables/lists/ObservableSet.java |  43 ++--
 47 files changed, 698 insertions(+), 420 deletions(-)
 create mode 100644 app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QObservable.java
 create 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/BufferViewConfigItem.java
 delete mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigWrapper.java
 create mode 100644 app/src/main/java/de/kuschku/util/observables/callbacks/DrawerItemCallback.java
 create mode 100644 app/src/main/java/de/kuschku/util/observables/callbacks/GeneralObservable.java
 create mode 100644 app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/MultiDrawerItemCallback.java
 rename app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/{GeneralCallbackWrapper.java => MultiGeneralCallback.java} (75%)

diff --git a/app/build.gradle b/app/build.gradle
index 37b2eb8c4..326276be9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -145,7 +145,7 @@ dependencies {
 
     // UI Libs
     compile(name:'library-release', ext:'aar')
-    compile('com.mikepenz:materialdrawer:5.0.0.b24-SNAPSHOT@aar') { transitive = true }
+    compile('com.mikepenz:materialdrawer:5.0.0.b25-SNAPSHOT@aar') { transitive = true }
     compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') { transitive = true }
     compile('com.github.afollestad.material-dialogs:commons:0.8.5.3@aar') { transitive = true }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/client/AClient.java b/app/src/main/java/de/kuschku/libquassel/client/AClient.java
index 92cc32996..8d78c7456 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/AClient.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/AClient.java
@@ -91,12 +91,12 @@ public abstract class AClient<T extends AClient<T>> extends SyncableObject<T> im
     }
 
     @Override
-    public void update(T from) {
+    public void _update(T from) {
         fail("This is not a real syncable");
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void _update(Map<String, QVariant> from) {
         fail("This is not a real syncable");
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java b/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java
index 8a9fdc020..5a76d6f3f 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java
@@ -35,6 +35,7 @@ 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.util.observables.lists.ObservableSet;
 
 import static de.kuschku.util.AndroidAssert.assertNotNull;
 
@@ -45,6 +46,8 @@ public class BufferManager {
 
     private final Map<String, Integer> buffersByNick = new HashMap<>();
     private final Map<String, Integer> buffersByChannel = new HashMap<>();
+    private final Map<Integer, ObservableSet<Integer>> buffersByNetwork = new HashMap<>();
+    private final ObservableSet<Integer> bufferIds = new ObservableSet<>();
 
     public BufferManager(Client client) {
         this.client = client;
@@ -52,11 +55,17 @@ public class BufferManager {
 
     public void createBuffer(@NonNull Buffer buffer) {
         buffers.put(buffer.getInfo().id(), buffer);
+        bufferIds.add(buffer.getInfo().id());
+        byNetwork(buffer.getInfo().networkId()).add(buffer.getInfo().id());
         updateBufferMapEntries(buffer, buffer.getInfo().name());
     }
 
     public void removeBuffer(@IntRange(from = 0) int id) {
+        Buffer buffer = buffers.get(id);
+        if (buffer != null)
+            byNetwork(buffer.getInfo().networkId()).remove(id);
         buffers.remove(id);
+        bufferIds.remove(id);
     }
 
     public Buffer buffer(@IntRange(from = 0) int id) {
@@ -66,6 +75,10 @@ public class BufferManager {
     public void updateBufferInfo(@NonNull BufferInfo bufferInfo) {
         Buffer buffer = buffer(bufferInfo.id());
         if (buffer == null) return;
+        if (buffer.getInfo().networkId() != bufferInfo.networkId()) {
+            buffersByNetwork.get(buffer.getInfo().networkId()).remove(bufferInfo.id());
+            buffersByNetwork.get(buffer.getInfo().networkId()).add(bufferInfo.id());
+        }
         buffer.setInfo(bufferInfo);
     }
 
@@ -127,4 +140,14 @@ public class BufferManager {
             return null;
         return (QueryBuffer) buffer;
     }
+
+    public ObservableSet<Integer> byNetwork(@IntRange(from = 0) int networkId) {
+        if (!buffersByNetwork.containsKey(networkId))
+            buffersByNetwork.put(networkId, new ObservableSet<>());
+        return buffersByNetwork.get(networkId);
+    }
+
+    public ObservableSet<Integer> bufferIds() {
+        return bufferIds;
+    }
 }
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 6ce6497cb..cc98ff191 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/Client.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/Client.java
@@ -135,7 +135,7 @@ public class Client extends AClient {
 
     @Override
     public void _displayMsg(Message msg) {
-        backlogStorage.insertMessages(msg);
+        backlogManager.receiveBacklog(msg);
     }
 
     @Override
@@ -358,6 +358,7 @@ public class Client extends AClient {
         if (bufferedSyncs.size() > 0) {
             String key = hashName(className, objectName);
             if (bufferedSyncs.containsKey(key)) {
+                Log.d("libquassel", "Unqueueing syncs: " + className + ":" + objectName);
                 List<SyncFunction> functions = bufferedSyncs.get(key);
                 for (SyncFunction function : functions)
                     provider.handle(function);
@@ -373,7 +374,7 @@ public class Client extends AClient {
 
     public void initBacklog(int id) {
         backlogRequests.remove((Integer) id);
-        if (backlogRequests.isEmpty())
+        if (backlogRequests.isEmpty() && connectionStatus() == ConnectionChangeEvent.Status.LOADING_BACKLOG)
             setConnectionStatus(ConnectionChangeEvent.Status.CONNECTED);
     }
 
@@ -442,16 +443,19 @@ public class Client extends AClient {
 
     public void bufferSync(@NonNull SyncFunction packedFunc) {
         String key = hashName(packedFunc.className, packedFunc.objectName);
-        if (connectionStatus() == ConnectionChangeEvent.Status.CONNECTED)
+        if (connectionStatus() == ConnectionChangeEvent.Status.CONNECTED) {
             Log.d("libquassel", "Queueing sync: " + packedFunc);
+        }
         if (!bufferedSyncs.containsKey(key))
             bufferedSyncs.put(key, new LinkedList<>());
         bufferedSyncs.get(key).add(packedFunc);
+        Log.d("libquassel", "Queued syncs: " + bufferedSyncs.keySet());
     }
 
     public void bufferBuffer(QBufferViewConfig bufferViewConfig, int bufferId, int pos) {
         bufferedBuffers.put(bufferId, Pair.create(bufferViewConfig, pos));
         Log.d("libquassel", "Queueing buffer: " + bufferId);
+        Log.d("libquassel", "Queued buffers: " + bufferedBuffers.keySet());
     }
 
     public void unbufferBuffer(BufferInfo info) {
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 9757b4c52..58f6d9bf1 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/NetworkManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/NetworkManager.java
@@ -32,10 +32,12 @@ import java.util.Observable;
 
 import de.kuschku.libquassel.syncables.types.impl.Network;
 import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
+import de.kuschku.util.observables.lists.ObservableSet;
 
 public class NetworkManager extends Observable {
     @NonNull
     private final Map<Integer, QNetwork> networks = new HashMap<>();
+    private final ObservableSet<QNetwork> list = new ObservableSet<>();
     private final Client client;
 
     public NetworkManager(Client client) {
@@ -47,8 +49,9 @@ public class NetworkManager extends Observable {
     }
 
     public void createNetwork(@NonNull QNetwork network) {
+        list.remove(networks.get(network.networkId()));
         networks.put(network.networkId(), network);
-        _update();
+        list.add(network);
     }
 
     public QNetwork network(@IntRange(from = 0) int networkId) {
@@ -56,8 +59,8 @@ public class NetworkManager extends Observable {
     }
 
     public void removeNetwork(@IntRange(from = 0) int network) {
+        list.remove(networks.get(network));
         networks.remove(network);
-        _update();
     }
 
 
@@ -66,16 +69,10 @@ public class NetworkManager extends Observable {
             createNetwork(networkId);
             client.requestInitObject("Network", String.valueOf(networkId));
         }
-        _update();
     }
 
-    private void _update() {
-        setChanged();
-        notifyObservers();
-    }
-
-    public void onDone(Runnable runnable) {
-
+    public ObservableSet<QNetwork> list() {
+        return list;
     }
 
     public List<QNetwork> networks() {
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/SyncableObject.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/SyncableObject.java
index 0913f4ea4..549f515ea 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/SyncableObject.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/SyncableObject.java
@@ -27,7 +27,6 @@ import android.support.annotation.Nullable;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Observable;
 
 import de.kuschku.libquassel.BusProvider;
 import de.kuschku.libquassel.client.Client;
@@ -36,12 +35,13 @@ import de.kuschku.libquassel.functions.types.SyncFunction;
 import de.kuschku.libquassel.primitives.types.QVariant;
 import de.kuschku.libquassel.syncables.types.interfaces.QSyncableObject;
 import de.kuschku.util.backports.Objects;
+import de.kuschku.util.observables.callbacks.GeneralObservable;
 
 import static de.kuschku.util.AndroidAssert.assertNotNull;
 import static de.kuschku.util.AndroidAssert.assertTrue;
 import static junit.framework.Assert.assertEquals;
 
-public abstract class SyncableObject<T extends SyncableObject<T>> extends Observable implements QSyncableObject<T> {
+public abstract class SyncableObject<T extends SyncableObject<T>> extends GeneralObservable implements QSyncableObject<T> {
     @Nullable
     protected BusProvider provider;
     protected Client client;
@@ -135,9 +135,6 @@ public abstract class SyncableObject<T extends SyncableObject<T>> extends Observ
     }
 
     public void _update() {
-        if (!hasChanged()) {
-            setChanged();
-            notifyObservers();
-        }
+        notifyChanged();
     }
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/AliasManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/AliasManager.java
index 95c530531..f462171ab 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/AliasManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/AliasManager.java
@@ -231,12 +231,12 @@ public class AliasManager extends AAliasManager<AliasManager> {
     }
 
     @Override
-    public void update(@NonNull Map<String, QVariant> from) {
-        update(AliasManagerSerializer.get().fromLegacy(from));
+    public void _update(@NonNull Map<String, QVariant> from) {
+        _update(AliasManagerSerializer.get().fromLegacy(from));
     }
 
     @Override
-    public void update(@NonNull AliasManager from) {
+    public void _update(@NonNull AliasManager from) {
         names = from.names;
         aliases = from.aliases;
         _update();
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BacklogManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BacklogManager.java
index 7feec17a2..8713723e0 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BacklogManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BacklogManager.java
@@ -21,6 +21,7 @@
 
 package de.kuschku.libquassel.syncables.types.impl;
 
+import android.support.annotation.IntRange;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
@@ -45,6 +46,8 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
     private final Client client;
     private final BacklogStorage storage;
     private final Set<Integer> initialized = new HashSet<>();
+    @IntRange(from = -1)
+    private int openBuffer;
 
     public BacklogManager(Client client, BacklogStorage storage) {
         this.client = client;
@@ -82,6 +85,8 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
         storage.insertMessages(id, messages.toArray(new Message[messages.size()]));
         client.initBacklog(id);
         provider.sendEvent(new BacklogReceivedEvent(id));
+        if (id == openBuffer && openBuffer != -1)
+            client.bufferSyncer().markBufferAsRead(openBuffer);
     }
 
     @Override
@@ -100,6 +105,8 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
         }
         for (int id : buffers) {
             provider.sendEvent(new BacklogReceivedEvent(id));
+            if (id == openBuffer && openBuffer != -1)
+                client.bufferSyncer().markBufferAsRead(openBuffer);
         }
     }
 
@@ -122,12 +129,26 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void open(int bufferId) {
+        openBuffer = bufferId;
+        if (bufferId != -1)
+            client.bufferSyncer().markBufferAsRead(bufferId);
+    }
+
+    @Override
+    public void receiveBacklog(Message msg) {
+        storage.insertMessages(msg);
+        if (msg.bufferInfo.id() == openBuffer && openBuffer != -1)
+            client.bufferSyncer().markBufferAsRead(openBuffer);
+    }
+
+    @Override
+    public void _update(Map<String, QVariant> from) {
 
     }
 
     @Override
-    public void update(BacklogManager from) {
+    public void _update(BacklogManager from) {
 
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferSyncer.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferSyncer.java
index 532883b2e..5330304fb 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferSyncer.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferSyncer.java
@@ -101,6 +101,7 @@ public class BufferSyncer extends ABufferSyncer<BufferSyncer> {
     public void _removeBuffer(int buffer) {
         markerLines.put(buffer, -1);
         lastSeenMsgs.put(buffer, -1);
+        client.bufferManager().removeBuffer(buffer);
         _update();
     }
 
@@ -155,12 +156,12 @@ public class BufferSyncer extends ABufferSyncer<BufferSyncer> {
     }
 
     @Override
-    public void update(@NonNull Map<String, QVariant> from) {
-        update(BufferSyncerSerializer.get().fromLegacy(from));
+    public void _update(@NonNull Map<String, QVariant> from) {
+        _update(BufferSyncerSerializer.get().fromLegacy(from));
     }
 
     @Override
-    public void update(@NonNull BufferSyncer from) {
+    public void _update(@NonNull BufferSyncer from) {
         lastSeenMsgs = from.lastSeenMsgs;
         markerLines = from.markerLines;
         _update();
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 da8830879..8ff71404a 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
@@ -26,7 +26,6 @@ import android.support.annotation.NonNull;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import de.kuschku.libquassel.BusProvider;
 import de.kuschku.libquassel.client.Client;
@@ -50,6 +49,7 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
     private boolean hideInactiveBuffers;
     private boolean hideInactiveNetworks;
     private ObservableList<Integer> buffers;
+    private ObservableSet<Integer> buffersIds;
     private ObservableSet<Integer> removedBuffers;
     private ObservableSet<Integer> temporarilyRemovedBuffers;
 
@@ -58,6 +58,7 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
         this.temporarilyRemovedBuffers = new ObservableSet<>(temporarilyRemovedBuffers);
         this.hideInactiveNetworks = hideInactiveNetworks;
         this.buffers = new ObservableList<>(buffers);
+        this.buffersIds = new ObservableSet<>(buffers);
         this.allowedBufferTypes = allowedBufferTypes;
         this.sortAlphabetically = sortAlphabetically;
         this.disableDecoration = disableDecoration;
@@ -203,12 +204,17 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
     }
 
     @Override
-    public Set<Integer> removedBuffers() {
+    public ObservableSet<Integer> bufferIds() {
+        return buffersIds;
+    }
+
+    @Override
+    public ObservableSet<Integer> removedBuffers() {
         return removedBuffers;
     }
 
     @Override
-    public Set<Integer> temporarilyRemovedBuffers() {
+    public ObservableSet<Integer> temporarilyRemovedBuffers() {
         return temporarilyRemovedBuffers;
     }
 
@@ -322,12 +328,12 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
     }
 
     @Override
-    public void update(@NonNull Map<String, QVariant> from) {
-        update(BufferViewConfigSerializer.get().fromLegacy(from));
+    public void _update(@NonNull Map<String, QVariant> from) {
+        _update(BufferViewConfigSerializer.get().fromLegacy(from));
     }
 
     @Override
-    public void update(@NonNull BufferViewConfig from) {
+    public void _update(@NonNull BufferViewConfig from) {
         this.bufferViewId = from.bufferViewId;
         this.bufferViewName = from.bufferViewName;
         this.networkId = from.networkId;
@@ -338,9 +344,14 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
         this.minimumActivity = from.minimumActivity;
         this.hideInactiveBuffers = from.hideInactiveBuffers;
         this.hideInactiveNetworks = from.hideInactiveNetworks;
-        this.buffers = from.buffers;
-        this.removedBuffers = from.removedBuffers;
-        this.temporarilyRemovedBuffers = from.temporarilyRemovedBuffers;
+        this.buffers.clear();
+        this.buffers.addAll(from.buffers);
+        this.buffersIds.retainAll(from.buffersIds);
+        this.buffersIds.addAll(from.buffersIds);
+        this.removedBuffers.retainAll(from.removedBuffers);
+        this.removedBuffers.addAll(from.removedBuffers);
+        this.temporarilyRemovedBuffers.retainAll(from.temporarilyRemovedBuffers);
+        this.temporarilyRemovedBuffers.addAll(from.temporarilyRemovedBuffers);
         _update();
     }
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewManager.java
index 5d95e2194..11ff20776 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/BufferViewManager.java
@@ -114,12 +114,12 @@ public class BufferViewManager extends ABufferViewManager<BufferViewManager> {
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void _update(Map<String, QVariant> from) {
 
     }
 
     @Override
-    public void update(@NonNull BufferViewManager from) {
+    public void _update(@NonNull BufferViewManager from) {
         this.bufferViewConfigs = from.bufferViewConfigs;
     }
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/CoreInfo.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/CoreInfo.java
index 3642474d3..af54c0c44 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/CoreInfo.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/CoreInfo.java
@@ -45,12 +45,12 @@ public class CoreInfo extends ACoreInfo<CoreInfo> {
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void _update(Map<String, QVariant> from) {
 
     }
 
     @Override
-    public void update(CoreInfo from) {
+    public void _update(CoreInfo from) {
 
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Identity.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Identity.java
index b0d9ac124..b7a81f271 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Identity.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Identity.java
@@ -386,11 +386,11 @@ public class Identity extends AIdentity<Identity> {
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void _update(Map<String, QVariant> from) {
     }
 
     @Override
-    public void update(Identity from) {
+    public void _update(Identity from) {
     }
 
     @Override
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IgnoreListManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IgnoreListManager.java
index 1e22403f3..cd6357971 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IgnoreListManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IgnoreListManager.java
@@ -134,12 +134,12 @@ public class IgnoreListManager extends AIgnoreListManager<IgnoreListManager> {
     }
 
     @Override
-    public void update(@NonNull Map<String, QVariant> from) {
-        update(IgnoreListManagerSerializer.get().fromDatastream(from));
+    public void _update(@NonNull Map<String, QVariant> from) {
+        _update(IgnoreListManagerSerializer.get().fromDatastream(from));
     }
 
     @Override
-    public void update(IgnoreListManager from) {
+    public void _update(IgnoreListManager from) {
 
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java
index bf9e3eb95..9c9bad616 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java
@@ -448,12 +448,12 @@ public class IrcChannel extends AIrcChannel<IrcChannel> {
     }
 
     @Override
-    public void update(@NonNull Map<String, QVariant> from) {
-        update(IrcChannelSerializer.get().fromDatastream(from));
+    public void _update(@NonNull Map<String, QVariant> from) {
+        _update(IrcChannelSerializer.get().fromDatastream(from));
     }
 
     @Override
-    public void update(IrcChannel from) {
+    public void _update(IrcChannel from) {
 
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcUser.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcUser.java
index 3b36b2ab0..c76bb718c 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcUser.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcUser.java
@@ -452,10 +452,10 @@ public class IrcUser extends AIrcUser<IrcUser> {
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void _update(Map<String, QVariant> from) {
     }
 
     @Override
-    public void update(IrcUser from) {
+    public void _update(IrcUser from) {
     }
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java
index 0d74ab0d6..c062cf6e0 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java
@@ -740,12 +740,12 @@ public class Network extends ANetwork<Network> implements Observer {
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void _update(Map<String, QVariant> from) {
 
     }
 
     @Override
-    public void update(Network from) {
+    public void _update(Network from) {
 
     }
 
@@ -762,7 +762,6 @@ public class Network extends ANetwork<Network> implements Observer {
         }
     }
 
-    @Override
     public void update(Observable observable, Object data) {
         _update();
     }
@@ -771,4 +770,28 @@ public class Network extends ANetwork<Network> implements Observer {
     public List<NetworkServer> serverList() {
         return networkInfo.serverList();
     }
+
+    @Override
+    public String toString() {
+        return "Network{" +
+                "name='" + networkInfo.networkName() + '\'' +
+                ", id='" + networkInfo.networkId() + '\'' +
+                '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Network network = (Network) o;
+
+        return networkInfo != null ? networkInfo.equals(network.networkInfo) : network.networkInfo == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return networkInfo != null ? networkInfo.hashCode() : 0;
+    }
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkConfig.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkConfig.java
index ff014fc92..74ffc10b3 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkConfig.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkConfig.java
@@ -175,12 +175,12 @@ public class NetworkConfig extends ANetworkConfig<NetworkConfig> {
     }
 
     @Override
-    public void update(Map<String, QVariant> from) {
+    public void _update(Map<String, QVariant> from) {
 
     }
 
     @Override
-    public void update(NetworkConfig from) {
+    public void _update(NetworkConfig from) {
 
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkInfo.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkInfo.java
index 435da1ab0..9d07c7d8a 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkInfo.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/NetworkInfo.java
@@ -289,4 +289,67 @@ public class NetworkInfo extends Observable {
         setChanged();
         notifyObservers();
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        NetworkInfo that = (NetworkInfo) o;
+
+        if (networkId != that.networkId) return false;
+        if (identity != that.identity) return false;
+        if (useRandomServer != that.useRandomServer) return false;
+        if (useAutoIdentify != that.useAutoIdentify) return false;
+        if (useSasl != that.useSasl) return false;
+        if (useAutoReconnect != that.useAutoReconnect) return false;
+        if (autoReconnectInterval != that.autoReconnectInterval) return false;
+        if (autoReconnectRetries != that.autoReconnectRetries) return false;
+        if (unlimitedReconnectRetries != that.unlimitedReconnectRetries) return false;
+        if (rejoinChannels != that.rejoinChannels) return false;
+        if (networkName != null ? !networkName.equals(that.networkName) : that.networkName != null)
+            return false;
+        if (codecForServer != null ? !codecForServer.equals(that.codecForServer) : that.codecForServer != null)
+            return false;
+        if (codecForEncoding != null ? !codecForEncoding.equals(that.codecForEncoding) : that.codecForEncoding != null)
+            return false;
+        if (codecForDecoding != null ? !codecForDecoding.equals(that.codecForDecoding) : that.codecForDecoding != null)
+            return false;
+        if (serverList != null ? !serverList.equals(that.serverList) : that.serverList != null)
+            return false;
+        if (perform != null ? !perform.equals(that.perform) : that.perform != null) return false;
+        if (autoIdentifyService != null ? !autoIdentifyService.equals(that.autoIdentifyService) : that.autoIdentifyService != null)
+            return false;
+        if (autoIdentifyPassword != null ? !autoIdentifyPassword.equals(that.autoIdentifyPassword) : that.autoIdentifyPassword != null)
+            return false;
+        if (saslAccount != null ? !saslAccount.equals(that.saslAccount) : that.saslAccount != null)
+            return false;
+        return saslPassword != null ? saslPassword.equals(that.saslPassword) : that.saslPassword == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = networkId;
+        result = 31 * result + (networkName != null ? networkName.hashCode() : 0);
+        result = 31 * result + identity;
+        result = 31 * result + (codecForServer != null ? codecForServer.hashCode() : 0);
+        result = 31 * result + (codecForEncoding != null ? codecForEncoding.hashCode() : 0);
+        result = 31 * result + (codecForDecoding != null ? codecForDecoding.hashCode() : 0);
+        result = 31 * result + (serverList != null ? serverList.hashCode() : 0);
+        result = 31 * result + (useRandomServer ? 1 : 0);
+        result = 31 * result + (perform != null ? perform.hashCode() : 0);
+        result = 31 * result + (useAutoIdentify ? 1 : 0);
+        result = 31 * result + (autoIdentifyService != null ? autoIdentifyService.hashCode() : 0);
+        result = 31 * result + (autoIdentifyPassword != null ? autoIdentifyPassword.hashCode() : 0);
+        result = 31 * result + (useSasl ? 1 : 0);
+        result = 31 * result + (saslAccount != null ? saslAccount.hashCode() : 0);
+        result = 31 * result + (saslPassword != null ? saslPassword.hashCode() : 0);
+        result = 31 * result + (useAutoReconnect ? 1 : 0);
+        result = 31 * result + autoReconnectInterval;
+        result = 31 * result + (int) autoReconnectRetries;
+        result = 31 * result + (unlimitedReconnectRetries ? 1 : 0);
+        result = 31 * result + (rejoinChannels ? 1 : 0);
+        return result;
+    }
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QAliasManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QAliasManager.java
index 60d748f87..bdc961c44 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QAliasManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QAliasManager.java
@@ -29,7 +29,7 @@ import de.kuschku.libquassel.objects.types.Command;
 import de.kuschku.libquassel.primitives.types.BufferInfo;
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QAliasManager {
+public interface QAliasManager extends QObservable {
     int indexOf(final String name);
 
     boolean contains(final String name);
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 be65a64fc..9c1428b0d 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
@@ -63,4 +63,8 @@ public interface QBacklogManager<T extends QSyncableObject<T>> extends QSyncable
 
     @Nullable
     ObservableComparableSortedList<Message> filtered(int id);
+
+    void open(int bufferId);
+
+    void receiveBacklog(Message msg);
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferSyncer.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferSyncer.java
index 53ece9137..31e63e09c 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferSyncer.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferSyncer.java
@@ -23,7 +23,7 @@ package de.kuschku.libquassel.syncables.types.interfaces;
 
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QBufferSyncer {
+public interface QBufferSyncer extends QObservable {
     int lastSeenMsg(int buffer);
 
     int markerLine(int buffer);
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 b6a1a276d..5ebe0c0e0 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
@@ -21,12 +21,11 @@
 
 package de.kuschku.libquassel.syncables.types.interfaces;
 
-import java.util.Set;
-
 import de.kuschku.libquassel.syncables.Synced;
 import de.kuschku.util.observables.lists.ObservableList;
+import de.kuschku.util.observables.lists.ObservableSet;
 
-public interface QBufferViewConfig {
+public interface QBufferViewConfig extends QObservable {
 
     int bufferViewId();
 
@@ -100,9 +99,11 @@ public interface QBufferViewConfig {
 
     ObservableList<Integer> bufferList();
 
-    Set<Integer> removedBuffers();
+    ObservableSet<Integer> bufferIds();
+
+    ObservableSet<Integer> removedBuffers();
 
-    Set<Integer> temporarilyRemovedBuffers();
+    ObservableSet<Integer> temporarilyRemovedBuffers();
 
     @Synced
     void addBuffer(final int bufferId, int pos);
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewManager.java
index 18457ceeb..1359b8421 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QBufferViewManager.java
@@ -27,7 +27,7 @@ import java.util.List;
 
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QBufferViewManager {
+public interface QBufferViewManager extends QObservable {
     @NonNull
     List<QBufferViewConfig> bufferViewConfigs();
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCertManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCertManager.java
index 2caeaccf4..aaf6e1af3 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCertManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCertManager.java
@@ -28,7 +28,7 @@ import java.security.cert.Certificate;
 
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QCertManager {
+public interface QCertManager extends QObservable {
     @NonNull
     PrivateKey sslKey();
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCoreInfo.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCoreInfo.java
index 07265cbe1..fe33e596b 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCoreInfo.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QCoreInfo.java
@@ -26,7 +26,7 @@ import java.util.Map;
 import de.kuschku.libquassel.primitives.types.QVariant;
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QCoreInfo {
+public interface QCoreInfo extends QObservable {
     Map<String, QVariant> coreData();
 
     @Synced
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIdentity.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIdentity.java
index fa0648161..18d60cb80 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIdentity.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIdentity.java
@@ -27,7 +27,7 @@ import java.util.List;
 
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QIdentity {
+public interface QIdentity extends QObservable {
     void setToDefaults();
 
     boolean isValid();
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIgnoreListManager.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIgnoreListManager.java
index 2210b81e8..a114509bc 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIgnoreListManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIgnoreListManager.java
@@ -26,7 +26,7 @@ import android.support.annotation.NonNull;
 import de.kuschku.libquassel.message.Message;
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QIgnoreListManager {
+public interface QIgnoreListManager extends QObservable {
     @Synced
     void requestRemoveIgnoreListItem(final String ignoreRule);
 
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java
index cabd22112..a1a406d57 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java
@@ -28,7 +28,7 @@ import java.util.List;
 import de.kuschku.libquassel.client.Client;
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QIrcChannel {
+public interface QIrcChannel extends QObservable {
     boolean isKnownUser(QIrcUser ircuser);
 
     boolean isValidChannelUserMode(final String mode);
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcUser.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcUser.java
index 333f593f3..2db4fa03f 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcUser.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcUser.java
@@ -30,7 +30,7 @@ import java.util.List;
 import de.kuschku.libquassel.client.Client;
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QIrcUser {
+public interface QIrcUser extends QObservable {
     String user();
 
     String host();
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java
index c4f6ce5eb..5ea8da726 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetwork.java
@@ -31,7 +31,7 @@ import de.kuschku.libquassel.syncables.Synced;
 import de.kuschku.libquassel.syncables.types.impl.IrcChannel;
 import de.kuschku.libquassel.syncables.types.impl.NetworkInfo;
 
-public interface QNetwork {
+public interface QNetwork extends QObservable {
     int networkId();
 
     boolean isMyNick(final String nick);
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetworkConfig.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetworkConfig.java
index 44f4aecb4..df591ca92 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetworkConfig.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QNetworkConfig.java
@@ -23,7 +23,7 @@ package de.kuschku.libquassel.syncables.types.interfaces;
 
 import de.kuschku.libquassel.syncables.Synced;
 
-public interface QNetworkConfig {
+public interface QNetworkConfig extends QObservable {
     boolean pingTimeoutEnabled();
 
     @Synced
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QObservable.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QObservable.java
new file mode 100644
index 000000000..f2950be79
--- /dev/null
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QObservable.java
@@ -0,0 +1,30 @@
+/*
+ * 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.libquassel.syncables.types.interfaces;
+
+import de.kuschku.util.observables.callbacks.GeneralCallback;
+
+public interface QObservable {
+    void addObserver(GeneralCallback o);
+
+    void deleteObserver(GeneralCallback o);
+}
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QSyncableObject.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QSyncableObject.java
index f45f7d02a..226850733 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QSyncableObject.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QSyncableObject.java
@@ -30,7 +30,7 @@ import de.kuschku.libquassel.BusProvider;
 import de.kuschku.libquassel.client.Client;
 import de.kuschku.libquassel.primitives.types.QVariant;
 
-public interface QSyncableObject<T extends QSyncableObject> {
+public interface QSyncableObject<T extends QSyncableObject> extends QObservable {
     void syncVar(@NonNull String methodName, @NonNull Object... params);
 
     void sync(@NonNull String methodName, @NonNull Object[] params);
@@ -39,9 +39,9 @@ public interface QSyncableObject<T extends QSyncableObject> {
 
     void rpc(@NonNull String procedureName, @NonNull Object[] params);
 
-    void update(Map<String, QVariant> from);
+    void _update(Map<String, QVariant> from);
 
-    void update(T from);
+    void _update(T from);
 
     void renameObject(String newName);
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.java
index 903312bb4..90a848ee9 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.java
@@ -95,7 +95,8 @@ import de.kuschku.quasseldroid_ng.R;
 import de.kuschku.quasseldroid_ng.service.ClientBackgroundThread;
 import de.kuschku.quasseldroid_ng.service.QuasselService;
 import de.kuschku.quasseldroid_ng.ui.chat.chatview.MessageAdapter;
-import de.kuschku.quasseldroid_ng.ui.chat.drawer.BufferViewConfigWrapper;
+import de.kuschku.quasseldroid_ng.ui.chat.drawer.BufferItem;
+import de.kuschku.quasseldroid_ng.ui.chat.drawer.BufferViewConfigItem;
 import de.kuschku.quasseldroid_ng.ui.editor.AdvancedEditor;
 import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
 import de.kuschku.quasseldroid_ng.ui.theme.AppTheme;
@@ -148,7 +149,7 @@ public class ChatActivity extends AppCompatActivity {
     private AccountHeader accountHeader;
     private Drawer drawerLeft;
     private AdvancedEditor editor;
-    private BufferViewConfigWrapper wrapper;
+    private BufferViewConfigItem wrapper;
     @Nullable
     private QuasselService.LocalBinder binder;
     @Nullable
@@ -491,10 +492,11 @@ public class ChatActivity extends AppCompatActivity {
                 if (((IExpandable) drawerItem).getSubItems() != null) {
                     drawerLeft.getAdapter().toggleExpandable(position);
                     return true;
-                } else {
-                    selectBuffer((int) drawerItem.getIdentifier());
+                } else if (drawerItem instanceof BufferItem) {
+                    selectBuffer(((BufferItem) drawerItem).getBuffer().getInfo().id());
                     return false;
                 }
+                return true;
             }
         });
     }
@@ -554,8 +556,6 @@ public class ChatActivity extends AppCompatActivity {
         status.bufferViewConfigId = bufferViewConfigId;
         accountHeader.setActiveProfile(bufferViewConfigId, false);
 
-        if (wrapper != null) wrapper.setDrawer(null);
-        drawerLeft.removeAllItems();
         if (bufferViewConfigId == -1) {
             drawerLeft.removeAllItems();
         } else {
@@ -565,12 +565,12 @@ public class ChatActivity extends AppCompatActivity {
             QBufferViewConfig viewConfig = bufferViewManager.bufferViewConfig(bufferViewConfigId);
             assertNotNull(viewConfig);
 
-            wrapper = new BufferViewConfigWrapper(context, viewConfig, drawerLeft);
-            wrapper.updateDrawerItems();
+            wrapper = new BufferViewConfigItem(drawerLeft, viewConfig, context);
         }
     }
 
     private void selectBuffer(@IntRange(from = -1) int bufferId) {
+        context.client().backlogManager().open(bufferId);
         if (bufferId == -1) {
             swipeView.setEnabled(false);
 
@@ -835,6 +835,9 @@ public class ChatActivity extends AppCompatActivity {
             if (context.provider() != null) {
                 context.provider().event.unregister(ChatActivity.this);
             }
+            if (context.client() != null) {
+                context.client().backlogManager().open(-1);
+            }
             context.setProvider(null);
             context.setClient(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
index 6099b57de..e616feef9 100644
--- 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
@@ -21,13 +21,11 @@
 
 package de.kuschku.quasseldroid_ng.ui.chat.drawer;
 
-import android.graphics.Color;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.view.View;
 import android.widget.TextView;
 
-import com.mikepenz.materialdrawer.holder.BadgeStyle;
 import com.mikepenz.materialdrawer.holder.ColorHolder;
 import com.mikepenz.materialdrawer.holder.ImageHolder;
 import com.mikepenz.materialdrawer.holder.StringHolder;
@@ -38,57 +36,19 @@ 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;
-import de.kuschku.util.observables.IObservable;
-import de.kuschku.util.observables.callbacks.GeneralCallback;
-import de.kuschku.util.observables.callbacks.wrappers.GeneralCallbackWrapper;
-import de.kuschku.util.observables.callbacks.wrappers.GeneralUICallbackWrapper;
-import de.kuschku.util.observables.lists.ObservableComparableSortedList;
 import de.kuschku.util.ui.MessageUtil;
 
-public class BufferItem extends SecondaryDrawerItem implements IObservable<GeneralCallback>, GeneralCallback {
+public class BufferItem extends SecondaryDrawerItem {
     @NonNull
     private final Buffer buffer;
     @NonNull
     private final AppContext context;
-    @NonNull
-    private final ObservableComparableSortedList<Message> notifications;
-
-    @NonNull
-    private final GeneralCallbackWrapper callback = new GeneralCallbackWrapper();
-
     public BufferItem(@NonNull Buffer buffer, @NonNull AppContext context) {
         this.buffer = buffer;
         this.context = context;
-        notifications = context.client().notificationManager().getNotifications(buffer.getInfo().id());
-        notifications.addCallback(new GeneralUICallbackWrapper() {
-            @Override
-            public void notifyChanged() {
-                BufferItem.this.notifyChanged();
-            }
-        });
-    }
-
-    public void notifyChanged() {
-        callback.notifyChanged();
-    }
-
-    @NonNull
-    @Override
-    public StringHolder getBadge() {
-        return new StringHolder(String.valueOf(notifications.size()));
-    }
-
-    @Override
-    public BadgeStyle getBadgeStyle() {
-        if (notifications.isEmpty()) {
-            return new BadgeStyle();
-        } else {
-            return new BadgeStyle().withTextColor(Color.WHITE).withColorRes(R.color.md_red_700);
-        }
     }
 
     @Override
@@ -159,16 +119,6 @@ public class BufferItem extends SecondaryDrawerItem implements IObservable<Gener
         return ColorHolder.fromColor(context.themeUtil().res.colorForegroundSecondary);
     }
 
-    @Override
-    public void addCallback(GeneralCallback callback) {
-        this.callback.addCallback(callback);
-    }
-
-    @Override
-    public void removeCallback(GeneralCallback callback) {
-        this.callback.removeCallback(callback);
-    }
-
     @NonNull
     public Buffer getBuffer() {
         return buffer;
@@ -176,7 +126,7 @@ public class BufferItem extends SecondaryDrawerItem implements IObservable<Gener
 
     @Override
     public long getIdentifier() {
-        return buffer.getInfo().id();
+        return buffer.getInfo().id() + buffer.getInfo().networkId() << 16;
     }
 
     @Override
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
new file mode 100644
index 000000000..de6fb515e
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferItemManager.java
@@ -0,0 +1,79 @@
+/*
+ * 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 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();
+
+    private final AppContext context;
+    private final Map<Integer, BufferItem> items = new HashMap<>();
+
+    public BufferItemManager(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/BufferViewConfigItem.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigItem.java
new file mode 100644
index 000000000..c52e2a714
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigItem.java
@@ -0,0 +1,112 @@
+/*
+ * 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.util.Log;
+
+import com.mikepenz.materialdrawer.Drawer;
+import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
+
+import java.util.HashSet;
+import java.util.Set;
+
+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.wrappers.AdapterUICallbackWrapper;
+import de.kuschku.util.observables.lists.ObservableComparableSortedList;
+
+public class BufferViewConfigItem implements DrawerItemCallback {
+    private final BufferItemManager manager;
+    private final ObservableComparableSortedList<NetworkItem> networks = new ObservableComparableSortedList<>(NetworkItem.class);
+    private final Drawer drawer;
+    private final QBufferViewConfig config;
+    private final AppContext context;
+
+    public BufferViewConfigItem(Drawer drawer, QBufferViewConfig config, AppContext context) {
+        this.drawer = drawer;
+        this.config = config;
+        this.context = context;
+        manager = new BufferItemManager(context);
+        config.addObserver(this::rebuildNetworkList);
+        networks.addCallback(new AdapterUICallbackWrapper(drawer.getItemAdapter()));
+        rebuildNetworkList();
+    }
+
+    private void rebuildNetworkList() {
+        // First we build a list of all network ids we want to display
+        Set<Integer> ids = new HashSet<>();
+        for (QNetwork network : context.client().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 (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) {
+            NetworkItem item = new NetworkItem(config, context.client(), manager, context.client().networkManager().network(id));
+            networks.add(item);
+            item.addCallback(this);
+        }
+        for (NetworkItem item : networks) {
+            if (ids.contains(item.getNetwork().networkId())) {
+                int position = networks.indexOf(item);
+                Log.d("libquassel", item + ":" + position);
+                drawer.addItemAtPosition(item, position);
+            }
+        }
+        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(IDrawerItem item) {
+        int position = drawer.getAdapter().getPosition(item);
+        if (position != -1) {
+            drawer.getAdapter().notifyAdapterItemChanged(position);
+            if (item instanceof NetworkItem)
+                drawer.getAdapter().notifyAdapterSubItemsChanged(position);
+        }
+    }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigWrapper.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigWrapper.java
deleted file mode 100644
index 0b8bd3510..000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/drawer/BufferViewConfigWrapper.java
+++ /dev/null
@@ -1,103 +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.ArrayList;
-
-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.lists.ObservableSortedList;
-
-public class BufferViewConfigWrapper {
-    @NonNull
-    private final ObservableSortedList<NetworkItem> networks = new ObservableSortedList<>(NetworkItem.class, new ObservableSortedList.ItemComparator<NetworkItem>() {
-        @Override
-        public int compare(@NonNull NetworkItem o1, @NonNull NetworkItem o2) {
-            return o1.getName().getText().compareTo(o2.getName().getText());
-        }
-
-        @Override
-        public boolean areContentsTheSame(NetworkItem item1, NetworkItem item2) {
-            return item1 == item2;
-        }
-
-        @Override
-        public boolean areItemsTheSame(@NonNull NetworkItem item1, @NonNull NetworkItem item2) {
-            return item1.getNetwork().networkId() == item2.getNetwork().networkId();
-        }
-    });
-    @NonNull
-    private final AppContext context;
-    @NonNull
-    private final QBufferViewConfig config;
-    private Drawer drawer;
-
-    public BufferViewConfigWrapper(@NonNull AppContext context, @NonNull QBufferViewConfig config, Drawer drawer) {
-        this.context = context;
-        this.config = config;
-        this.drawer = drawer;
-        updateNetworks();
-    }
-
-    public void updateNetworks() {
-        networks.clear();
-        if (config.networkId() != 0)
-            networks.add(new NetworkItem(context, context.client().networkManager().network(config.networkId()), config));
-        else
-            for (QNetwork network : context.client().networkManager().networks())
-                networks.add(new NetworkItem(context, network, config));
-    }
-
-    public void updateDrawerItems() {
-        drawer.removeAllItems();
-        for (IDrawerItem item : getItems()) {
-            drawer.addItem(item);
-        }
-        for (int i = 0; i < drawer.getAdapter().getItemCount(); i++) {
-            IDrawerItem item = drawer.getAdapter().getItem(i);
-            if (item instanceof NetworkItem) {
-                NetworkItem networkItem = (NetworkItem) item;
-                if (networkItem.getNetwork().isConnected())
-                    drawer.getAdapter().expand(i);
-            }
-        }
-    }
-
-    public void setDrawer(Drawer drawer) {
-        this.drawer = drawer;
-    }
-
-    @NonNull
-    public ArrayList<IDrawerItem> getItems() {
-        ArrayList<IDrawerItem> items = new ArrayList<>();
-        for (IDrawerItem item : networks) {
-            items.add(item);
-        }
-        return items;
-    }
-}
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 f0a5c4a81..619280296 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
@@ -22,8 +22,6 @@
 package de.kuschku.quasseldroid_ng.ui.chat.drawer;
 
 import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.SparseArray;
 
 import com.mikepenz.materialdrawer.holder.StringHolder;
 import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
@@ -32,206 +30,99 @@ import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
 import java.util.ArrayList;
 import java.util.List;
 
-import de.kuschku.libquassel.localtypes.buffers.Buffer;
-import de.kuschku.libquassel.primitives.types.BufferInfo;
+import de.kuschku.libquassel.client.Client;
 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.ContentComparable;
 import de.kuschku.util.observables.IObservable;
-import de.kuschku.util.observables.callbacks.GeneralCallback;
-import de.kuschku.util.observables.callbacks.UICallback;
-import de.kuschku.util.observables.callbacks.wrappers.GeneralCallbackWrapper;
-import de.kuschku.util.observables.lists.ObservableSortedList;
-
-import static de.kuschku.libquassel.primitives.types.BufferInfo.Type.CHANNEL;
-import static de.kuschku.libquassel.primitives.types.BufferInfo.Type.GROUP;
-import static de.kuschku.libquassel.primitives.types.BufferInfo.Type.QUERY;
-import static de.kuschku.libquassel.primitives.types.BufferInfo.Type.STATUS;
-
-public class NetworkItem extends PrimaryDrawerItem implements IObservable<GeneralCallback>, GeneralCallback {
-    @NonNull
+import de.kuschku.util.observables.callbacks.DrawerItemCallback;
+import de.kuschku.util.observables.callbacks.ElementCallback;
+import de.kuschku.util.observables.callbacks.wrappers.MultiDrawerItemCallback;
+
+public class NetworkItem extends PrimaryDrawerItem implements IObservable<DrawerItemCallback>, ContentComparable<NetworkItem> {
+    private final QBufferViewConfig config;
+    private final Client client;
+    private final BufferItemManager manager;
     private final QNetwork network;
-    @NonNull
-    private final ObservableSortedList<BufferItem> buffers = new ObservableSortedList<>(BufferItem.class, new AlphabeticalComparator());
-    @NonNull
-    private final SparseArray<BufferItem> bufferIds = new SparseArray<>();
-    @NonNull
-    private final GeneralCallbackWrapper callback = new GeneralCallbackWrapper();
-
-    public NetworkItem(@NonNull AppContext context, @NonNull QNetwork network, @NonNull QBufferViewConfig config) {
-        this.network = network;
-
-        for (Integer bufferId : config.bufferList()) {
-            Buffer buffer = context.client().bufferManager().buffer(bufferId);
-            if (buffer != null && buffer.getInfo().networkId() == network.networkId()) {
-                this.buffers.add(new BufferItem(buffer, context));
-            }
-        }
-        config.bufferList().addCallback(new UICallback() {
-            @Override
-            public void notifyItemInserted(int position) {
-                int element = config.bufferList().get(position);
-                Buffer buffer = context.client().bufferManager().buffer(element);
-                if (buffer.getInfo().networkId() == network.networkId()) {
-                    if (bufferIds.get(element) == null) {
-                        BufferItem bufferItem = new BufferItem(buffer, context);
-                        buffers.add(bufferItem);
-                        bufferItem.addCallback(NetworkItem.this);
-                        bufferIds.put(element, bufferItem);
-                        notifyChanged();
-                    }
-                }
-            }
-
-            @Override
-            public void notifyItemChanged(int position) {
-                int element = config.bufferList().get(position);
-                if (bufferIds.get(element) != null) {
-                    notifyChanged();
-                }
-            }
-
-            @Override
-            public void notifyItemRemoved(int position) {
-                int element = config.bufferList().get(position);
-                if (bufferIds.get(element) != null) {
-                    bufferIds.remove(element);
-                    notifyChanged();
-                }
-            }
-
-            @Override
-            public void notifyItemMoved(int from, int to) {
-                notifyItemChanged(from);
-                notifyItemChanged(to);
-            }
+    private final MultiDrawerItemCallback callback = MultiDrawerItemCallback.of();
 
+    public NetworkItem(QBufferViewConfig config, Client client, BufferItemManager manager, QNetwork network) {
+        this.config = config;
+        this.client = client;
+        this.manager = manager;
+        this.network = network;
+        ElementCallback<Integer> elemCallback = new ElementCallback<Integer>() {
             @Override
-            public void notifyItemRangeInserted(int position, int count) {
-                for (int i = position; i < position + count; i++)
-                    notifyItemInserted(i);
+            public void notifyItemInserted(Integer element) {
+                callback.notifyChanged(NetworkItem.this);
             }
 
             @Override
-            public void notifyItemRangeChanged(int position, int count) {
-                for (int i = position; i < position + count; i++)
-                    notifyItemChanged(i);
+            public void notifyItemRemoved(Integer element) {
+                callback.notifyChanged(NetworkItem.this);
             }
 
             @Override
-            public void notifyItemRangeRemoved(int position, int count) {
-                for (int i = position; i < position + count; i++)
-                    notifyItemRemoved(i);
+            public void notifyItemChanged(Integer element) {
+                callback.notifyChanged(manager.get(element));
             }
-        });
+        };
+        config.bufferIds().addCallback(elemCallback);
+        client.bufferManager().byNetwork(network.networkId()).addCallback(elemCallback);
     }
 
-    @NonNull
     @Override
-    public StringHolder getDescription() {
-        return new StringHolder(String.valueOf(network.latency()));
+    public List<IDrawerItem> getSubItems() {
+        List<IDrawerItem> bufferItems = new ArrayList<>();
+        for (int id : config.bufferList()) {
+            if (client.bufferManager().byNetwork(network.networkId()).contains(id)) {
+                bufferItems.add(manager.get(id));
+            }
+        }
+        return bufferItems;
     }
 
-    @Nullable
     @Override
     public StringHolder getName() {
         return new StringHolder(network.networkName());
     }
 
-    @NonNull
     @Override
-    public List<IDrawerItem> getSubItems() {
-        ArrayList<IDrawerItem> items = new ArrayList<>();
-        for (IDrawerItem item : buffers) {
-            items.add(item);
-        }
-        return items;
+    public void addCallback(DrawerItemCallback callback) {
+        this.callback.addCallback(callback);
     }
 
     @Override
-    public void notifyChanged() {
-        this.callback.notifyChanged();
+    public void removeCallback(DrawerItemCallback callback) {
+        this.callback.removeCallback(callback);
     }
 
     @Override
-    public void addCallback(GeneralCallback callback) {
-        this.callback.addCallback(callback);
+    public boolean areItemsTheSame(NetworkItem other) {
+        return network.networkId() == other.network.networkId();
     }
 
     @Override
-    public void removeCallback(GeneralCallback callback) {
-        this.callback.removeCallback(callback);
+    public boolean areContentsTheSame(NetworkItem other) {
+        return network.equals(other);
+    }
+
+    @Override
+    public int compareTo(@NonNull NetworkItem another) {
+        return network.networkName().compareTo(another.network.networkName());
     }
 
-    @NonNull
     public QNetwork getNetwork() {
         return network;
     }
 
     @Override
-    public long getIdentifier() {
-        return network.networkId();
-    }
-
-    class AlphabeticalComparator implements ObservableSortedList.ItemComparator<BufferItem> {
-        @Override
-        public int compare(@NonNull BufferItem o1, @NonNull BufferItem o2) {
-            BufferInfo.Type type1 = o1.getBuffer().getInfo().type();
-            BufferInfo.Type type2 = o2.getBuffer().getInfo().type();
-            if (type1 == type2) {
-                if (o1.getBuffer().getName() == null)
-                    return -1;
-                else if (o2.getBuffer().getName() == null)
-                    return 1;
-                else
-                    return o1.getBuffer().getName().compareTo(o2.getBuffer().getName());
-            } else {
-                // Type1 is status, Type2 isn’t
-                if (type1 == STATUS) return -1;
-                // Type2 is status, Type1 isn’t
-                if (type2 == STATUS) return 1;
-                // Type1 is channel, Type2 isn’t
-                if (type1 == CHANNEL) return -1;
-                // Type2 is channel, Type1 isn’t
-                if (type2 == CHANNEL) return 1;
-                // Type1 is group, Type2 isn’t
-                if (type1 == GROUP) return -1;
-                // Type2 is group, Type1 isn’t
-                if (type2 == GROUP) return 1;
-                // Type1 is query, Type2 isn’t
-                if (type1 == QUERY) return -1;
-                // Type2 is query, Type1 isn’t
-                if (type2 == QUERY) return 1;
-                // Per default, keep order
-                return -1;
-            }
-        }
-
-        @Override
-        public boolean areContentsTheSame(BufferItem item1, BufferItem item2) {
-            return item1 == item2;
-        }
-
-        @Override
-        public boolean areItemsTheSame(@NonNull BufferItem item1, @NonNull BufferItem item2) {
-            return item1.getBuffer().getInfo().id() == item2.getBuffer().getInfo().id();
-        }
+    public String toString() {
+        return String.valueOf(network);
     }
 
-    class NoneComparator implements ObservableSortedList.ItemComparator<BufferItem> {
-        @Override
-        public int compare(@NonNull BufferItem o1, @NonNull BufferItem o2) {
-            return o1.getBuffer().getInfo().id() - o2.getBuffer().getInfo().id();
-        }
-
-        @Override
-        public boolean areContentsTheSame(BufferItem item1, BufferItem item2) {
-            return item1 == item2;
-        }
-
-        @Override
-        public boolean areItemsTheSame(@NonNull BufferItem item1, @NonNull BufferItem item2) {
-            return item1.getBuffer().getInfo().id() == item2.getBuffer().getInfo().id();
-        }
+    @Override
+    public long getIdentifier() {
+        return network.networkId() << 16;
     }
 }
diff --git a/app/src/main/java/de/kuschku/util/observables/callbacks/DrawerItemCallback.java b/app/src/main/java/de/kuschku/util/observables/callbacks/DrawerItemCallback.java
new file mode 100644
index 000000000..054c5d36d
--- /dev/null
+++ b/app/src/main/java/de/kuschku/util/observables/callbacks/DrawerItemCallback.java
@@ -0,0 +1,28 @@
+/*
+ * 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.util.observables.callbacks;
+
+import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
+
+public interface DrawerItemCallback {
+    void notifyChanged(IDrawerItem item);
+}
diff --git a/app/src/main/java/de/kuschku/util/observables/callbacks/GeneralObservable.java b/app/src/main/java/de/kuschku/util/observables/callbacks/GeneralObservable.java
new file mode 100644
index 000000000..b4b7086ac
--- /dev/null
+++ b/app/src/main/java/de/kuschku/util/observables/callbacks/GeneralObservable.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util.observables.callbacks;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import de.kuschku.libquassel.syncables.types.interfaces.QObservable;
+
+public class GeneralObservable implements QObservable, GeneralCallback {
+    Set<GeneralCallback> callbackSet = new HashSet<>();
+
+    @Override
+    public void addObserver(GeneralCallback o) {
+        callbackSet.add(o);
+    }
+
+    @Override
+    public void deleteObserver(GeneralCallback o) {
+        callbackSet.remove(o);
+    }
+
+
+    @Override
+    public void notifyChanged() {
+        for (GeneralCallback callback : callbackSet) {
+            callback.notifyChanged();
+        }
+    }
+}
diff --git a/app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/MultiDrawerItemCallback.java b/app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/MultiDrawerItemCallback.java
new file mode 100644
index 000000000..5c47b2bc3
--- /dev/null
+++ b/app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/MultiDrawerItemCallback.java
@@ -0,0 +1,64 @@
+/*
+ * 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.util.observables.callbacks.wrappers;
+
+import android.support.annotation.NonNull;
+
+import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import de.kuschku.util.observables.IObservable;
+import de.kuschku.util.observables.callbacks.DrawerItemCallback;
+
+public class MultiDrawerItemCallback implements DrawerItemCallback, IObservable<DrawerItemCallback> {
+    @NonNull
+    final Set<DrawerItemCallback> callbacks;
+
+    private MultiDrawerItemCallback(List<DrawerItemCallback> multiGeneralCallbacks) {
+        this.callbacks = new HashSet<>(multiGeneralCallbacks);
+    }
+
+    public static MultiDrawerItemCallback of(DrawerItemCallback... callbacks) {
+        return new MultiDrawerItemCallback(Arrays.asList(callbacks));
+    }
+
+    @Override
+    public void notifyChanged(IDrawerItem item) {
+        for (DrawerItemCallback callback : callbacks) {
+            callback.notifyChanged(item);
+        }
+    }
+
+    @Override
+    public void addCallback(DrawerItemCallback callback) {
+        callbacks.add(callback);
+    }
+
+    @Override
+    public void removeCallback(DrawerItemCallback callback) {
+        callbacks.remove(callback);
+    }
+}
diff --git a/app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/GeneralCallbackWrapper.java b/app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/MultiGeneralCallback.java
similarity index 75%
rename from app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/GeneralCallbackWrapper.java
rename to app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/MultiGeneralCallback.java
index bac1847e4..1519d2956 100644
--- a/app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/GeneralCallbackWrapper.java
+++ b/app/src/main/java/de/kuschku/util/observables/callbacks/wrappers/MultiGeneralCallback.java
@@ -23,15 +23,25 @@ package de.kuschku.util.observables.callbacks.wrappers;
 
 import android.support.annotation.NonNull;
 
+import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import de.kuschku.util.observables.IObservable;
 import de.kuschku.util.observables.callbacks.GeneralCallback;
 
-public class GeneralCallbackWrapper implements IObservable<GeneralCallback>, GeneralCallback {
+public class MultiGeneralCallback implements IObservable<GeneralCallback>, GeneralCallback {
     @NonNull
-    final Set<GeneralCallback> callbacks = new HashSet<>();
+    final Set<GeneralCallback> callbacks;
+
+    private MultiGeneralCallback(List<MultiGeneralCallback> multiGeneralCallbacks) {
+        this.callbacks = new HashSet<>(multiGeneralCallbacks);
+    }
+
+    public static MultiGeneralCallback of(MultiGeneralCallback... callbacks) {
+        return new MultiGeneralCallback(Arrays.asList(callbacks));
+    }
 
     @Override
     public void notifyChanged() {
diff --git a/app/src/main/java/de/kuschku/util/observables/lists/ObservableComparableSortedList.java b/app/src/main/java/de/kuschku/util/observables/lists/ObservableComparableSortedList.java
index b12279b59..ddbc9a149 100644
--- a/app/src/main/java/de/kuschku/util/observables/lists/ObservableComparableSortedList.java
+++ b/app/src/main/java/de/kuschku/util/observables/lists/ObservableComparableSortedList.java
@@ -23,10 +23,12 @@ package de.kuschku.util.observables.lists;
 
 import android.support.annotation.NonNull;
 
+import java.util.List;
+
 import de.kuschku.util.observables.ContentComparable;
 import de.kuschku.util.observables.callbacks.UICallback;
 
-public class ObservableComparableSortedList<T extends ContentComparable<T>> extends ObservableSortedList<T> implements IObservableList<UICallback, T> {
+public class ObservableComparableSortedList<T extends ContentComparable<T>> extends ObservableSortedList<T> implements IObservableList<UICallback, T>, List<T> {
 
 
     public ObservableComparableSortedList(@NonNull Class<T> cl) {
diff --git a/app/src/main/java/de/kuschku/util/observables/lists/ObservableList.java b/app/src/main/java/de/kuschku/util/observables/lists/ObservableList.java
index e5d7660cb..099f9c033 100644
--- a/app/src/main/java/de/kuschku/util/observables/lists/ObservableList.java
+++ b/app/src/main/java/de/kuschku/util/observables/lists/ObservableList.java
@@ -124,6 +124,13 @@ public class ObservableList<T> extends ArrayList<T> implements IObservableList<U
         return -1;
     }
 
+    @Override
+    public void clear() {
+        int size = size();
+        super.clear();
+        callback.notifyItemRangeRemoved(0, size);
+    }
+
     @NonNull
     @Override
     public Iterator<T> iterator() {
diff --git a/app/src/main/java/de/kuschku/util/observables/lists/ObservableSet.java b/app/src/main/java/de/kuschku/util/observables/lists/ObservableSet.java
index 6ae47e992..0f7b99e57 100644
--- a/app/src/main/java/de/kuschku/util/observables/lists/ObservableSet.java
+++ b/app/src/main/java/de/kuschku/util/observables/lists/ObservableSet.java
@@ -22,7 +22,6 @@
 package de.kuschku.util.observables.lists;
 
 import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -31,58 +30,69 @@ import java.util.Iterator;
 import de.kuschku.util.observables.callbacks.ElementCallback;
 import de.kuschku.util.observables.callbacks.wrappers.MultiElementCallbackWrapper;
 
+import static de.kuschku.util.AndroidAssert.assertNotNull;
+
 @SuppressWarnings("unchecked")
 public class ObservableSet<T> extends HashSet<T> implements IObservableSet<ElementCallback<T>, T> {
-    @Nullable
+    @NonNull
     private final MultiElementCallbackWrapper<T> callback = MultiElementCallbackWrapper.<T>of();
 
     public ObservableSet(int capacity) {
         super(capacity);
+        assertNotNull(this.callback);
     }
 
     public ObservableSet() {
         super();
+        assertNotNull(this.callback);
     }
 
     public ObservableSet(@NonNull Collection<? extends T> collection) {
-        super(collection);
+        assertNotNull(this.callback);
+
+        assertNotNull(callback);
     }
 
     public void addCallback(@NonNull ElementCallback<T> callback) {
-        if (this.callback != null)
-            this.callback.addCallback(callback);
+        assertNotNull(this.callback);
+
+        this.callback.addCallback(callback);
     }
 
     public void removeCallback(@NonNull ElementCallback<T> callback) {
-        if (this.callback != null)
-            this.callback.removeCallback(callback);
+        assertNotNull(this.callback);
+
+        this.callback.removeCallback(callback);
     }
 
     @Override
     public boolean add(T object) {
+        assertNotNull(this.callback);
+
         boolean result = super.add(object);
-        if (callback != null)
-            callback.notifyItemInserted(object);
+        callback.notifyItemInserted(object);
         return result;
     }
 
     @Override
     public boolean addAll(@NonNull Collection<? extends T> collection) {
+        assertNotNull(this.callback);
+
         boolean result = super.addAll(collection);
         if (result)
             for (T element : collection)
-                if (callback != null)
-                    callback.notifyItemInserted(element);
+                callback.notifyItemInserted(element);
         return result;
     }
 
     @Override
     public boolean remove(Object object) {
+        assertNotNull(this.callback);
+
         boolean contains = contains(object);
         if (contains) {
-            remove(object);
-            if (callback != null)
-                callback.notifyItemRemoved((T) object);
+            super.remove(object);
+            callback.notifyItemRemoved((T) object);
             return true;
         } else {
             return false;
@@ -116,9 +126,10 @@ public class ObservableSet<T> extends HashSet<T> implements IObservableSet<Eleme
 
         @Override
         public void remove() {
+            assertNotNull(callback);
+
             iterator.remove();
-            if (callback != null)
-                callback.notifyItemRemoved((T) current);
+            callback.notifyItemRemoved((T) current);
         }
     }
 }
-- 
GitLab