From 6b8f35fa4c9b5bb94703843fa4f5b08c5a5c91e9 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Fri, 26 Aug 2016 23:52:30 +0200
Subject: [PATCH] Hybrid Backlog Storage created Created first version of
 hybrid (memory and db) backed backlog storage, which keeps only the current
 buffer in memory, and all other buffers on disk, even between reconnects.

---
 app/build.gradle                              |  30 ++--
 .../libquassel/client/BufferManager.java      |  26 +--
 .../de/kuschku/libquassel/client/Client.java  |  10 +-
 .../libquassel/localtypes/BacklogFilter.java  |   6 +-
 .../localtypes/NotificationManager.java       |   2 +-
 .../backlogstorage/BacklogStorage.java        |   4 +
 .../backlogstorage/HybridBacklogStorage.java  | 156 ++++++++++++++++++
 .../backlogstorage/MemoryBacklogStorage.java  |  19 ++-
 .../localtypes/buffers/Buffers.java           |   2 +-
 .../localtypes/buffers/ChannelBuffer.java     |  10 +-
 .../localtypes/buffers/QueryBuffer.java       |  10 +-
 .../localtypes/buffers/StatusBuffer.java      |   8 +-
 .../localtypes/orm/ConnectedDatabase.java     |   9 +
 .../orm/converters/BufferTypeConverter.java   |  18 ++
 .../orm/converters/DateTimeConverter.java     |  18 ++
 .../orm/converters/MessageFlagsConverter.java |  18 ++
 .../orm/converters/MessageTypeConverter.java  |  18 ++
 .../kuschku/libquassel/message/Message.java   |  79 +++++----
 .../serializers/BufferInfoSerializer.java     |  12 +-
 .../serializers/MessageSerializer.java        |   4 +-
 .../primitives/types/BufferInfo.java          |  82 ++++-----
 .../serializers/IrcUserSerializer.java        |   2 +
 .../serializers/NetworkSerializer.java        |   1 +
 .../types/abstracts/AIgnoreListManager.java   |   2 +-
 .../syncables/types/abstracts/AIrcUser.java   |   6 +
 .../syncables/types/impl/AliasManager.java    |   6 +-
 .../syncables/types/impl/BacklogManager.java  |  26 ++-
 .../syncables/types/impl/BufferSyncer.java    |  10 +-
 .../types/impl/BufferViewConfig.java          |   6 +-
 .../syncables/types/impl/IrcUser.java         |  17 +-
 .../syncables/types/interfaces/QIrcUser.java  |   7 +
 .../quasseldroid_ng/QuasselDroidNG.java       |   7 +
 .../service/ClientBackgroundThread.java       |   4 +-
 .../ui/chat/ChannelDetailActivity.java        |   2 +-
 .../quasseldroid_ng/ui/chat/MainActivity.java |  16 +-
 .../ui/chat/chatview/ChatMessageRenderer.java |   2 +-
 .../chat/drawer/BufferViewConfigAdapter.java  |   1 +
 .../ui/chat/drawer/BufferViewHolder.java      |   8 +-
 .../ui/chat/drawer/NetworkItem.java           |  20 +--
 .../ui/chat/util/ScrollRefreshLayout.java     |  36 ++++
 .../java/de/kuschku/util/AndroidAssert.java   |   4 +-
 .../util/irc/format/IrcFormatHelper.java      |   4 +-
 .../util/servicebound/BoundActivity.java      |   8 +-
 app/src/main/res/layout/fragment_chat.xml     |   4 +-
 app/src/main/res/layout/slide.xml             |   6 +-
 .../main/res/layout/slide_account_core.xml    |   7 +-
 .../main/res/layout/widget_chatmessage.xml    |   2 +-
 app/src/main/res/values/strings.xml           |  14 +-
 48 files changed, 563 insertions(+), 206 deletions(-)
 create mode 100644 app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java
 create mode 100644 app/src/main/java/de/kuschku/libquassel/localtypes/orm/ConnectedDatabase.java
 create mode 100644 app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/BufferTypeConverter.java
 create mode 100644 app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/DateTimeConverter.java
 create mode 100644 app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageFlagsConverter.java
 create mode 100644 app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageTypeConverter.java
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ScrollRefreshLayout.java

diff --git a/app/build.gradle b/app/build.gradle
index 89d0b1465..fe0ce963f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -20,8 +20,8 @@
  */
 
 apply plugin: 'com.android.application'
-apply plugin: 'com.neenbedankt.android-apt'
 apply plugin: 'me.tatarka.retrolambda'
+apply plugin: 'com.neenbedankt.android-apt'
 
 dependencies {
     repositories {
@@ -72,13 +72,13 @@ if (versionPropsFile.exists() && versionPropsFile.canRead()) {
 def rawVersionName = "0.2.0"
 
 android {
-    compileSdkVersion 23
-    buildToolsVersion "23.0.2"
+    compileSdkVersion 24
+    buildToolsVersion "24.0.0"
     
     defaultConfig {
-        applicationId "de.kuschku.quasseldroid_ng"
+        applicationId "com.iskrembilen.quasseldroid"
         minSdkVersion 16
-        targetSdkVersion 23
+        targetSdkVersion 24
         versionCode versionBuild
         versionName rawVersionName + " Build #" + versionBuild
     }
@@ -154,14 +154,18 @@ dependencies {
     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 }
 
-    compile 'com.android.support:appcompat-v7:23.1.1'
-    compile 'com.android.support:design:23.1.1'
-    compile 'com.android.support:support-v4:23.1.1'
-    compile 'com.android.support:recyclerview-v7:23.1.1'
-    compile 'com.android.support:preference-v14:23.1.1'
-    compile 'com.android.support:cardview-v7:23.1.1'
+    // ORM
+    apt "com.github.Raizlabs.DBFlow:dbflow-processor:3.1.1"
+    compile "com.github.Raizlabs.DBFlow:dbflow-core:3.1.1"
+    compile "com.github.Raizlabs.DBFlow:dbflow:3.1.1"
+
+    compile 'com.android.support:appcompat-v7:24.0.0'
+    compile 'com.android.support:design:24.0.0'
+    compile 'com.android.support:support-v4:24.0.0'
+    compile 'com.android.support:recyclerview-v7:24.0.0'
+    compile 'com.android.support:preference-v14:24.0.0'
+    compile 'com.android.support:cardview-v7:24.0.0'
 
     // UI autobinding
-    compile 'com.jakewharton:butterknife:8.0.0-SNAPSHOT'
-    apt 'com.jakewharton:butterknife-compiler:8.0.0-SNAPSHOT'
+    compile 'com.jakewharton:butterknife:7.0.1'
 }
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 7e4042db5..832b84ff6 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/BufferManager.java
@@ -62,16 +62,16 @@ 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());
+        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);
+            byNetwork(buffer.getInfo().networkId).remove(id);
         buffers.remove(id);
         bufferIds.remove(id);
     }
@@ -81,11 +81,11 @@ public class BufferManager {
     }
 
     public void updateBufferInfo(@NonNull BufferInfo bufferInfo) {
-        Buffer buffer = buffer(bufferInfo.id());
+        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());
+        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);
     }
@@ -93,7 +93,7 @@ public class BufferManager {
     public void init(@NonNull List<BufferInfo> bufferInfos) {
         for (BufferInfo info : bufferInfos) {
             createBuffer(info);
-            laterRequests.add(info.id());
+            laterRequests.add(info.id);
         }
     }
 
@@ -109,7 +109,7 @@ public class BufferManager {
     }
 
     public boolean exists(@NonNull BufferInfo info) {
-        return buffers.containsKey(info.id());
+        return buffers.containsKey(info.id);
     }
 
     public void renameBuffer(int bufferId, @NonNull String newName) {
@@ -123,9 +123,9 @@ public class BufferManager {
         buffersByNick.remove(buffer.objectName());
         buffersByChannel.remove(buffer.objectName());
         if (buffer instanceof ChannelBuffer) {
-            buffersByChannel.put(buffer.objectName(name), buffer.getInfo().id());
+            buffersByChannel.put(buffer.objectName(name), buffer.getInfo().id);
         } else if (buffer instanceof QueryBuffer) {
-            buffersByNick.put(buffer.objectName(name), buffer.getInfo().id());
+            buffersByNick.put(buffer.objectName(name), buffer.getInfo().id);
         }
     }
 
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 09fd97c12..fe51a75ae 100644
--- a/app/src/main/java/de/kuschku/libquassel/client/Client.java
+++ b/app/src/main/java/de/kuschku/libquassel/client/Client.java
@@ -460,12 +460,12 @@ public class Client extends AClient {
     public void unbufferBuffer(@NonNull BufferInfo info) {
         if (!bufferManager().exists(info)) {
             bufferManager().createBuffer(info);
-            Log.d("libquassel", "Creating buffer from message info: " + info.id());
+            Log.d("libquassel", "Creating buffer from message info: " + info.id);
         }
-        if (bufferedBuffers.containsKey(info.id())) {
-            Pair<QBufferViewConfig, Integer> pair = bufferedBuffers.get(info.id());
-            pair.first._addBuffer(info.id(), pair.second);
-            Log.d("libquassel", "Un-Queueing buffer: " + info.id());
+        if (bufferedBuffers.containsKey(info.id)) {
+            Pair<QBufferViewConfig, Integer> pair = bufferedBuffers.get(info.id);
+            pair.first._addBuffer(info.id, pair.second);
+            Log.d("libquassel", "Un-Queueing buffer: " + info.id);
         }
     }
 
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 c5e2b7ac1..e251540c8 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java
@@ -74,12 +74,12 @@ public class BacklogFilter implements UICallback {
     private void updateDayChangeMessages() {
         DateTime now = DateTime.now().withMillisOfDay(0);
         while (now.isAfter(earliestMessage)) {
-            bus.post(new MessageInsertEvent(new Message(
+            bus.post(new MessageInsertEvent(Message.create(
                     (int) DateTimeUtils.toJulianDay(now.getMillis()),
                     now,
                     Message.Type.DayChange,
                     new Message.Flags(false, false, false, false, false),
-                    new BufferInfo(
+                    BufferInfo.create(
                             bufferId,
                             -1,
                             BufferInfo.Type.INVALID,
@@ -94,7 +94,7 @@ public class BacklogFilter implements UICallback {
     }
 
     private boolean filterItem(@NonNull Message message) {
-        QNetwork network = client.networkManager().network(client.bufferManager().buffer(message.bufferInfo.id()).getInfo().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/NotificationManager.java b/app/src/main/java/de/kuschku/libquassel/localtypes/NotificationManager.java
index d270922ee..ff0e7e0d4 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/NotificationManager.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/NotificationManager.java
@@ -58,7 +58,7 @@ public class NotificationManager {
 
     public void receiveMessage(@NonNull Message message) {
         if (checkMessage(message)) {
-            getNotifications(message.bufferInfo.id()).add(message);
+            getNotifications(message.bufferInfo.id).add(message);
         }
     }
 
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/BacklogStorage.java b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/BacklogStorage.java
index 34b15a618..95ef6c34e 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/BacklogStorage.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/BacklogStorage.java
@@ -46,4 +46,8 @@ public interface BacklogStorage {
     void insertMessages(Message... messages);
 
     void setClient(Client client);
+
+    void markBufferUnused(@IntRange(from = 0) int bufferid);
+
+    void clear(@IntRange(from = 0) int bufferid);
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java
new file mode 100644
index 000000000..0127826da
--- /dev/null
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java
@@ -0,0 +1,156 @@
+/*
+ * 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.localtypes.backlogstorage;
+
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.util.SparseArray;
+
+import com.raizlabs.android.dbflow.config.FlowManager;
+import com.raizlabs.android.dbflow.sql.language.SQLite;
+import com.raizlabs.android.dbflow.structure.database.DatabaseWrapper;
+import com.raizlabs.android.dbflow.structure.database.transaction.ITransaction;
+
+import java.util.List;
+
+import de.kuschku.libquassel.client.Client;
+import de.kuschku.libquassel.localtypes.BacklogFilter;
+import de.kuschku.libquassel.localtypes.orm.ConnectedDatabase;
+import de.kuschku.libquassel.message.Message;
+import de.kuschku.libquassel.message.Message_Table;
+import de.kuschku.util.observables.lists.ObservableComparableSortedList;
+
+import static de.kuschku.util.AndroidAssert.assertNotNull;
+
+public class HybridBacklogStorage implements BacklogStorage {
+    @NonNull
+    private final SparseArray<ObservableComparableSortedList<Message>> backlogs = new SparseArray<>();
+    @NonNull
+    private final SparseArray<ObservableComparableSortedList<Message>> filteredBacklogs = new SparseArray<>();
+    @NonNull
+    private final SparseArray<BacklogFilter> filters = new SparseArray<>();
+    @NonNull
+    private final SparseArray<Integer> latestMessage = new SparseArray<>();
+
+    private Client client;
+
+    @NonNull
+    @Override
+    public ObservableComparableSortedList<Message> getUnfiltered(@IntRange(from = -1) int bufferid) {
+        ensureExisting(bufferid);
+        return backlogs.get(bufferid);
+    }
+
+    @NonNull
+    @Override
+    public ObservableComparableSortedList<Message> getFiltered(@IntRange(from = -1) int bufferid) {
+        ensureExisting(bufferid);
+        return filteredBacklogs.get(bufferid);
+    }
+
+    @NonNull
+    @Override
+    public BacklogFilter getFilter(int bufferid) {
+        ensureExisting(bufferid);
+        return filters.get(bufferid);
+    }
+
+    @Override
+    public int getLatest(@IntRange(from = 0) int bufferid) {
+        return latestMessage.get(bufferid, -1);
+    }
+
+    @Override
+    public void insertMessages(@IntRange(from = 0) int bufferId, @NonNull Message... messages) {
+        ensureExisting(bufferId);
+        FlowManager.getDatabase(ConnectedDatabase.class).executeTransaction(new ITransaction() {
+            @Override
+            public void execute(DatabaseWrapper databaseWrapper) {
+                for (Message message : messages) {
+                    client.unbufferBuffer(message.bufferInfo);
+                    synchronized (backlogs) {
+                        if (backlogs.get(bufferId) != null)
+                            backlogs.get(bufferId).add(message);
+                        message.save();
+                        message.bufferInfo.save();
+                    }
+                    updateLatest(message);
+                }
+            }
+        });
+    }
+
+    public void updateLatest(@NonNull Message message) {
+        if (message.id > getLatest(message.bufferInfo.id)) {
+            latestMessage.put(message.bufferInfo.id, message.id);
+        }
+    }
+
+    @Override
+    public void insertMessages(@NonNull Message... messages) {
+        for (Message message : messages) {
+            client.unbufferBuffer(message.bufferInfo);
+            synchronized (backlogs) {
+                if (backlogs.get(message.bufferInfo.id) != null)
+                    backlogs.get(message.bufferInfo.id).add(message);
+            }
+            updateLatest(message);
+        }
+    }
+
+    public void setClient(Client client) {
+        this.client = client;
+    }
+
+    @Override
+    public void markBufferUnused(@IntRange(from = 0) int bufferid) {
+        synchronized (backlogs) {
+            if (backlogs.get(bufferid) != null && filters.get(bufferid) != null)
+                backlogs.get(bufferid).removeCallback(filters.get(bufferid));
+            backlogs.remove(bufferid);
+            filteredBacklogs.remove(bufferid);
+            filters.remove(bufferid);
+        }
+    }
+
+    @Override
+    public void clear(@IntRange(from = 0) int bufferid) {
+        SQLite.delete().from(Message.class).where(Message_Table.bufferInfo_id.eq(bufferid));
+    }
+
+    private void ensureExisting(@IntRange(from = -1) int bufferId) {
+        assertNotNull(client);
+        if (backlogs.get(bufferId) == null) {
+            ObservableComparableSortedList<Message> messages = new ObservableComparableSortedList<>(Message.class, true);
+            ObservableComparableSortedList<Message> filteredMessages = new ObservableComparableSortedList<>(Message.class, true);
+            BacklogFilter backlogFilter = new BacklogFilter(client, bufferId, messages, filteredMessages);
+            messages.addCallback(backlogFilter);
+            synchronized (backlogs) {
+                List<Message> messageList = SQLite.select().from(Message.class).where(Message_Table.bufferInfo_id.eq(bufferId)).queryList();
+                messages.addAll(messageList);
+                backlogs.put(bufferId, messages);
+            }
+            filteredBacklogs.put(bufferId, filteredMessages);
+            filters.put(bufferId, backlogFilter);
+        }
+    }
+}
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/MemoryBacklogStorage.java b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/MemoryBacklogStorage.java
index c887d11ad..462354cb5 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/MemoryBacklogStorage.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/MemoryBacklogStorage.java
@@ -81,17 +81,17 @@ public class MemoryBacklogStorage implements BacklogStorage {
     }
 
     public void updateLatest(@NonNull Message message) {
-        if (message.messageId > getLatest(message.bufferInfo.id())) {
-            latestMessage.put(message.bufferInfo.id(), message.messageId);
+        if (message.id > getLatest(message.bufferInfo.id)) {
+            latestMessage.put(message.bufferInfo.id, message.id);
         }
     }
 
     @Override
     public void insertMessages(@NonNull Message... messages) {
         for (Message message : messages) {
-            ensureExisting(message.bufferInfo.id());
+            ensureExisting(message.bufferInfo.id);
             client.unbufferBuffer(message.bufferInfo);
-            backlogs.get(message.bufferInfo.id()).add(message);
+            backlogs.get(message.bufferInfo.id).add(message);
             updateLatest(message);
         }
     }
@@ -100,6 +100,17 @@ public class MemoryBacklogStorage implements BacklogStorage {
         this.client = client;
     }
 
+    @Override
+    public void markBufferUnused(@IntRange(from = 0) int bufferid) {
+        // Does nothing in memory backlog storage
+    }
+
+    @Override
+    public void clear(@IntRange(from = 0) int bufferid) {
+        ensureExisting(bufferid);
+        backlogs.get(bufferid).clear();
+    }
+
     private void ensureExisting(@IntRange(from = -1) int bufferId) {
         assertNotNull(client);
         if (backlogs.get(bufferId) == null) {
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffers.java b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffers.java
index a1ab5b5b7..dcbd564f9 100644
--- a/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffers.java
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/buffers/Buffers.java
@@ -34,7 +34,7 @@ public class Buffers {
 
     @Nullable
     public static Buffer fromType(@NonNull BufferInfo info, @NonNull Client client) {
-        switch (info.type()) {
+        switch (info.type) {
             case QUERY:
                 return new QueryBuffer(info, client);
             case CHANNEL:
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 cf00f0ce0..f90033596 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
@@ -56,7 +56,7 @@ public class ChannelBuffer implements Buffer {
     @Nullable
     @Override
     public String getName() {
-        return getInfo().name();
+        return getInfo().name;
     }
 
     @NonNull
@@ -69,24 +69,24 @@ public class ChannelBuffer implements Buffer {
 
     @Override
     public void renameBuffer(@NonNull String newName) {
-        info.setName(newName);
+        info.name = newName;
     }
 
     @NonNull
     @Override
     public String objectName() {
-        return objectName(info.name());
+        return objectName(info.name);
     }
 
     @NonNull
     @Override
     public String objectName(String name) {
-        return info.networkId() + "/" + name;
+        return info.networkId + "/" + name;
     }
 
     @Nullable
     public QIrcChannel getChannel() {
-        return client.networkManager().network(info.networkId()).ircChannel(info.name());
+        return client.networkManager().network(info.networkId).ircChannel(info.name);
     }
 
     @NonNull
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 89a507257..a87f00a1f 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
@@ -56,7 +56,7 @@ public class QueryBuffer implements Buffer {
     @Nullable
     @Override
     public String getName() {
-        return getInfo().name();
+        return getInfo().name;
     }
 
     @NonNull
@@ -71,24 +71,24 @@ public class QueryBuffer implements Buffer {
 
     @Override
     public void renameBuffer(@NonNull String newName) {
-        info.setName(newName);
+        info.name = newName;
     }
 
     @NonNull
     @Override
     public String objectName() {
-        return objectName(info.name());
+        return objectName(info.name);
     }
 
     @NonNull
     @Override
     public String objectName(String name) {
-        return info.networkId() + "/" + name;
+        return info.networkId + "/" + name;
     }
 
     @Nullable
     public QIrcUser getUser() {
-        return client.networkManager().network(info.networkId()).ircUser(info.name());
+        return client.networkManager().network(info.networkId).ircUser(info.name);
     }
 
     @NonNull
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 5828b6306..72ae63042 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
@@ -53,7 +53,7 @@ public class StatusBuffer implements Buffer {
     }
 
     public QNetwork getNetwork() {
-        return client.networkManager().network(info.networkId());
+        return client.networkManager().network(info.networkId);
     }
 
     @Nullable
@@ -73,18 +73,18 @@ public class StatusBuffer implements Buffer {
     @NonNull
     @Override
     public String objectName() {
-        return objectName(info.name());
+        return objectName(info.name);
     }
 
     @NonNull
     @Override
     public String objectName(String name) {
-        return info.networkId() + "/" + name;
+        return info.networkId + "/" + name;
     }
 
     @Override
     public void renameBuffer(@NonNull String newName) {
-        this.info.setName(newName);
+        this.info.name = newName;
     }
 
     @NonNull
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/orm/ConnectedDatabase.java b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/ConnectedDatabase.java
new file mode 100644
index 000000000..b2205a929
--- /dev/null
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/ConnectedDatabase.java
@@ -0,0 +1,9 @@
+package de.kuschku.libquassel.localtypes.orm;
+
+import com.raizlabs.android.dbflow.annotation.Database;
+
+@Database(name = ConnectedDatabase.NAME, version = ConnectedDatabase.VERSION)
+public class ConnectedDatabase {
+    public static final String NAME = "ConnectedDatabase";
+    public static final int VERSION = 2;
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/BufferTypeConverter.java b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/BufferTypeConverter.java
new file mode 100644
index 000000000..6ce247793
--- /dev/null
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/BufferTypeConverter.java
@@ -0,0 +1,18 @@
+package de.kuschku.libquassel.localtypes.orm.converters;
+
+import com.raizlabs.android.dbflow.converter.TypeConverter;
+
+import de.kuschku.libquassel.primitives.types.BufferInfo;
+
+@com.raizlabs.android.dbflow.annotation.TypeConverter
+public class BufferTypeConverter extends TypeConverter<Short, BufferInfo.Type> {
+    @Override
+    public Short getDBValue(BufferInfo.Type model) {
+        return model.id;
+    }
+
+    @Override
+    public BufferInfo.Type getModelValue(Short data) {
+        return BufferInfo.Type.fromId(data);
+    }
+}
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/DateTimeConverter.java b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/DateTimeConverter.java
new file mode 100644
index 000000000..280ac445c
--- /dev/null
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/DateTimeConverter.java
@@ -0,0 +1,18 @@
+package de.kuschku.libquassel.localtypes.orm.converters;
+
+import com.raizlabs.android.dbflow.converter.TypeConverter;
+
+import org.joda.time.DateTime;
+
+@com.raizlabs.android.dbflow.annotation.TypeConverter
+public class DateTimeConverter extends TypeConverter<Long, DateTime> {
+    @Override
+    public Long getDBValue(DateTime model) {
+        return model.getMillis();
+    }
+
+    @Override
+    public DateTime getModelValue(Long data) {
+        return new DateTime(data.longValue());
+    }
+}
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageFlagsConverter.java b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageFlagsConverter.java
new file mode 100644
index 000000000..b3f1d9b18
--- /dev/null
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageFlagsConverter.java
@@ -0,0 +1,18 @@
+package de.kuschku.libquassel.localtypes.orm.converters;
+
+import com.raizlabs.android.dbflow.converter.TypeConverter;
+
+import de.kuschku.libquassel.message.Message;
+
+@com.raizlabs.android.dbflow.annotation.TypeConverter
+public class MessageFlagsConverter extends TypeConverter<Short, Message.Flags> {
+    @Override
+    public Short getDBValue(Message.Flags model) {
+        return (short) model.flags;
+    }
+
+    @Override
+    public Message.Flags getModelValue(Short data) {
+        return new Message.Flags(data.byteValue());
+    }
+}
diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageTypeConverter.java b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageTypeConverter.java
new file mode 100644
index 000000000..3327777ff
--- /dev/null
+++ b/app/src/main/java/de/kuschku/libquassel/localtypes/orm/converters/MessageTypeConverter.java
@@ -0,0 +1,18 @@
+package de.kuschku.libquassel.localtypes.orm.converters;
+
+import com.raizlabs.android.dbflow.converter.TypeConverter;
+
+import de.kuschku.libquassel.message.Message;
+
+@com.raizlabs.android.dbflow.annotation.TypeConverter
+public class MessageTypeConverter extends TypeConverter<Integer, Message.Type> {
+    @Override
+    public Integer getDBValue(Message.Type model) {
+        return model.value;
+    }
+
+    @Override
+    public Message.Type getModelValue(Integer data) {
+        return Message.Type.fromId(data);
+    }
+}
diff --git a/app/src/main/java/de/kuschku/libquassel/message/Message.java b/app/src/main/java/de/kuschku/libquassel/message/Message.java
index 487c8b0dd..3534ac918 100644
--- a/app/src/main/java/de/kuschku/libquassel/message/Message.java
+++ b/app/src/main/java/de/kuschku/libquassel/message/Message.java
@@ -24,45 +24,49 @@ package de.kuschku.libquassel.message;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
+import com.raizlabs.android.dbflow.annotation.Column;
+import com.raizlabs.android.dbflow.annotation.ForeignKey;
+import com.raizlabs.android.dbflow.annotation.PrimaryKey;
+import com.raizlabs.android.dbflow.annotation.Table;
+import com.raizlabs.android.dbflow.structure.BaseModel;
+
 import org.joda.time.DateTime;
 
 import java.io.Serializable;
 import java.util.Comparator;
 
+import de.kuschku.libquassel.localtypes.orm.ConnectedDatabase;
 import de.kuschku.libquassel.primitives.types.BufferInfo;
 import de.kuschku.util.observables.ContentComparable;
 
-public class Message implements ContentComparable<Message> {
-    public final int messageId;
-    @NonNull
-    public final DateTime time;
-    @NonNull
-    public final Type type;
-    @NonNull
-    public final Flags flags;
-    @NonNull
-    public final BufferInfo bufferInfo;
-    @Nullable
-    public final String sender;
-    @Nullable
-    public final String content;
-
-    public Message(int messageId, @NonNull DateTime time, @NonNull Type type, @NonNull Flags flags, @NonNull BufferInfo bufferInfo, @Nullable String sender,
-                   @Nullable String content) {
-        this.messageId = messageId;
-        this.time = time;
-        this.type = type;
-        this.flags = flags;
-        this.bufferInfo = bufferInfo;
-        this.sender = sender;
-        this.content = content;
-    }
+@Table(database = ConnectedDatabase.class)
+public class Message extends BaseModel implements ContentComparable<Message> {
+    @PrimaryKey
+    public int id;
+
+    @Column
+    public DateTime time;
+
+    @Column
+    public Type type;
+
+    @Column
+    public Flags flags;
+
+    @ForeignKey
+    public BufferInfo bufferInfo;
+
+    @Column
+    public String sender;
+
+    @Column
+    public String content;
 
     @NonNull
     @Override
     public String toString() {
         return "Message{" +
-                "messageId=" + messageId +
+                "id=" + id +
                 ", time=" + time +
                 ", type=" + type +
                 ", flags=" + flags +
@@ -79,22 +83,34 @@ public class Message implements ContentComparable<Message> {
 
     @Override
     public boolean areItemsTheSame(@NonNull Message other) {
-        return this.messageId == other.messageId;
+        return this.id == other.id;
     }
 
     @Override
     public int hashCode() {
-        return messageId;
+        return id;
     }
 
     @Override
     public int compareTo(@NonNull Message another) {
         if (this.type != Type.DayChange && another.type != Type.DayChange)
-            return this.messageId - another.messageId;
+            return this.id - another.id;
         else
             return this.time.compareTo(another.time);
     }
 
+    public static Message create(int id, DateTime time, Type type, Flags flags, BufferInfo bufferInfo, String sender, String content) {
+        Message message = new Message();
+        message.id = id;
+        message.time = time;
+        message.type = type;
+        message.flags = flags;
+        message.bufferInfo = bufferInfo;
+        message.sender = sender;
+        message.content = content;
+        return message;
+    }
+
     public enum Type {
         Plain(0x00001),
         Notice(0x00002),
@@ -164,6 +180,7 @@ public class Message implements ContentComparable<Message> {
                     return Error;
             }
         }
+
     }
 
     public static class Flags {
@@ -212,12 +229,13 @@ public class Message implements ContentComparable<Message> {
             output.append("]");
             return output.toString();
         }
+
     }
 
     public static class MessageComparator implements Comparator<Message>, Serializable {
         @Override
         public int compare(@NonNull Message o1, @NonNull Message o2) {
-            return o1.messageId - o2.messageId;
+            return o1.id - o2.id;
         }
 
         @Override
@@ -225,4 +243,5 @@ public class Message implements ContentComparable<Message> {
             return obj == this;
         }
     }
+
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java
index a6fc89548..0e838f015 100644
--- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java
+++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java
@@ -43,17 +43,17 @@ public class BufferInfoSerializer implements PrimitiveSerializer<BufferInfo> {
 
     @Override
     public void serialize(@NonNull ByteChannel channel, @NonNull BufferInfo data) throws IOException {
-        IntSerializer.get().serialize(channel, data.id());
-        IntSerializer.get().serialize(channel, data.networkId());
-        ShortSerializer.get().serialize(channel, data.type().id);
-        IntSerializer.get().serialize(channel, data.groupId());
-        ByteArraySerializer.get().serialize(channel, data.name());
+        IntSerializer.get().serialize(channel, data.id);
+        IntSerializer.get().serialize(channel, data.networkId);
+        ShortSerializer.get().serialize(channel, data.type.id);
+        IntSerializer.get().serialize(channel, data.groupId);
+        ByteArraySerializer.get().serialize(channel, data.name);
     }
 
     @NonNull
     @Override
     public BufferInfo deserialize(@NonNull final ByteBuffer buffer) throws IOException {
-        return new BufferInfo(
+        return BufferInfo.create(
                 IntSerializer.get().deserialize(buffer),
                 IntSerializer.get().deserialize(buffer),
                 BufferInfo.Type.fromId(ShortSerializer.get().deserialize(buffer)),
diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java
index e552ee77c..9e7b73796 100644
--- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java
+++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java
@@ -47,7 +47,7 @@ public class MessageSerializer implements PrimitiveSerializer<Message> {
 
     @Override
     public void serialize(@NonNull ByteChannel channel, @NonNull Message data) throws IOException {
-        IntSerializer.get().serialize(channel, data.messageId);
+        IntSerializer.get().serialize(channel, data.id);
         IntSerializer.get().serialize(channel, (int) (data.time.getMillis() / 1000));
         IntSerializer.get().serialize(channel, data.type.value);
         ByteSerializer.get().serialize(channel, data.flags.flags);
@@ -67,7 +67,7 @@ public class MessageSerializer implements PrimitiveSerializer<Message> {
         String sender = ByteArraySerializer.get().deserialize(buffer);
         String message = ByteArraySerializer.get().deserialize(buffer);
 
-        return new Message(
+        return Message.create(
                 messageId,
                 time,
                 type,
diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/types/BufferInfo.java b/app/src/main/java/de/kuschku/libquassel/primitives/types/BufferInfo.java
index de1fe2a29..473325e5a 100644
--- a/app/src/main/java/de/kuschku/libquassel/primitives/types/BufferInfo.java
+++ b/app/src/main/java/de/kuschku/libquassel/primitives/types/BufferInfo.java
@@ -24,64 +24,30 @@ package de.kuschku.libquassel.primitives.types;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
-public class BufferInfo {
-    private int id;
-    private int networkId;
-    @NonNull
-    private Type type;
-    private int groupId;
-    @Nullable
-    private String name;
-
-    public BufferInfo(int id, int networkId, @NonNull Type type, int groupId, @Nullable String name) {
-        this.id = id;
-        this.networkId = networkId;
-        this.type = type;
-        this.groupId = groupId;
-        this.name = name;
-    }
+import com.raizlabs.android.dbflow.annotation.Column;
+import com.raizlabs.android.dbflow.annotation.PrimaryKey;
+import com.raizlabs.android.dbflow.annotation.Table;
+import com.raizlabs.android.dbflow.converter.TypeConverter;
+import com.raizlabs.android.dbflow.structure.BaseModel;
 
-    public int id() {
-        return id;
-    }
+import de.kuschku.libquassel.localtypes.orm.ConnectedDatabase;
 
-    public void setId(int id) {
-        this.id = id;
-    }
+@Table(database = ConnectedDatabase.class)
+public class BufferInfo extends BaseModel {
+    @PrimaryKey
+    public int id;
 
-    public int networkId() {
-        return networkId;
-    }
+    @Column
+    public int networkId;
 
-    public void setNetworkId(int networkId) {
-        this.networkId = networkId;
-    }
+    @Column
+    public Type type;
 
-    @NonNull
-    public Type type() {
-        return type;
-    }
+    @Column
+    public int groupId;
 
-    public void setType(@NonNull Type type) {
-        this.type = type;
-    }
-
-    public int groupId() {
-        return groupId;
-    }
-
-    public void setGroupId(int groupId) {
-        this.groupId = groupId;
-    }
-
-    @Nullable
-    public String name() {
-        return name;
-    }
-
-    public void setName(@Nullable String name) {
-        this.name = name;
-    }
+    @Column
+    public String name;
 
     @NonNull
     @Override
@@ -95,6 +61,16 @@ public class BufferInfo {
                 '}';
     }
 
+    public static BufferInfo create(int id, int networkId, Type type, int groupId, String name) {
+        BufferInfo info = new BufferInfo();
+        info.id = id;
+        info.networkId = networkId;
+        info.type = type;
+        info.groupId = groupId;
+        info.name = name;
+        return info;
+    }
+
     public enum Type {
         INVALID(0x00),
         STATUS(0x01),
@@ -127,6 +103,7 @@ public class BufferInfo {
                     return INVALID;
             }
         }
+
     }
 
     public enum BufferStatus {
@@ -141,4 +118,5 @@ public class BufferInfo {
         MESSAGES,
         HIGHLIGHTS
     }
+
 }
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java
index 6b9a3f288..498c5701e 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java
@@ -66,6 +66,7 @@ public class IrcUserSerializer implements ObjectSerializer<IrcUser> {
         map.data.put("suserHost", new QVariant<>(data.suserHost()));
         map.data.put("nick", new QVariant<>(data.nick()));
         map.data.put("realName", new QVariant<>(data.realName()));
+        map.data.put("account", new QVariant<>(data.account()));
         map.data.put("awayMessage", new QVariant<>(data.awayMessage()));
         map.data.put("loginTime", new QVariant<>(data.loginTime()));
         map.data.put("encrypted", new QVariant<>(data.encrypted()));
@@ -95,6 +96,7 @@ public class IrcUserSerializer implements ObjectSerializer<IrcUser> {
                 (String) map.get("suserHost").data,
                 (String) map.get("nick").data,
                 (String) map.get("realName").data,
+                (String) map.get("account").data,
                 (String) map.get("awayMessage").data,
                 (DateTime) map.get("loginTime").data,
                 (boolean) map.get("encrypted").data,
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java
index 6dbacc8a7..f68c1ed38 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java
@@ -115,6 +115,7 @@ public class NetworkSerializer implements ObjectSerializer<Network> {
                         (String) users.get("suserHost").data.get(i),
                         (String) users.get("nick").data.get(i),
                         (String) users.get("realName").data.get(i),
+                        (String) users.get("account").data.get(i),
                         (String) users.get("awayMessage").data.get(i),
                         (DateTime) users.get("loginTime").data.get(i),
                         (boolean) users.get("encrypted").data.get(i),
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 2677b2004..603385e55 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
@@ -80,6 +80,6 @@ public abstract class AIgnoreListManager<T extends AIgnoreListManager<T>> extend
     @Override
     public boolean matches(Message message, QNetwork network) {
         assertNotNull(network);
-        return match(message.content, message.sender, message.type, network.networkName(), message.bufferInfo.name()) != StrictnessType.UnmatchedStrictness;
+        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/abstracts/AIrcUser.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/abstracts/AIrcUser.java
index f6dfb6100..04bc72d06 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/abstracts/AIrcUser.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/abstracts/AIrcUser.java
@@ -54,6 +54,12 @@ public abstract class AIrcUser<T extends AIrcUser<T>> extends SyncableObject<T>
         syncVar("setRealName", realName);
     }
 
+    @Override
+    public void setAccount(String account) {
+        _setAccount(account);
+        syncVar("setAccount", account);
+    }
+
     @Override
     public void setAway(boolean away) {
         _setAway(away);
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 f462171ab..3a6e7865c 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
@@ -109,8 +109,8 @@ public class AliasManager extends AAliasManager<AliasManager> {
                 command = command.replaceAll(String.format(Locale.US, "$%d", j), params.get(j - 1));
             }
             command = command.replaceAll("\\$0", args);
-            command = command.replaceAll("\\$channelname", info.name() != null ? info.name() : "");
-            command = command.replaceAll("\\$channel", info.name() != null ? info.name() : "");
+            command = command.replaceAll("\\$channelname", info.name != null ? info.name : "");
+            command = command.replaceAll("\\$channel", info.name != null ? info.name : "");
             command = command.replaceAll("\\$currentnick", network.myNick());
             command = command.replaceAll("\\$nick", network.myNick());
             command = command.replaceAll("\\$network", network.networkName());
@@ -204,7 +204,7 @@ public class AliasManager extends AAliasManager<AliasManager> {
                 args = message.substring(space + 1);
             }
             int index = indexOfIgnoreCase(command);
-            QNetwork network = client.networkManager().network(info.networkId());
+            QNetwork network = client.networkManager().network(info.networkId);
             if (index != -1 && network != null) {
                 Alias alias = aliases.get(index);
                 list.addAll(expand(alias.expansion, info, network, args));
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 605b2f9d6..62c97c1f0 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
@@ -23,6 +23,9 @@ package de.kuschku.libquassel.syncables.types.impl;
 
 import android.support.annotation.IntRange;
 import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.raizlabs.android.dbflow.sql.language.SQLite;
 
 import java.util.HashSet;
 import java.util.List;
@@ -38,6 +41,7 @@ import de.kuschku.libquassel.events.ConnectionChangeEvent;
 import de.kuschku.libquassel.localtypes.BacklogFilter;
 import de.kuschku.libquassel.localtypes.backlogstorage.BacklogStorage;
 import de.kuschku.libquassel.message.Message;
+import de.kuschku.libquassel.message.Message_Table;
 import de.kuschku.libquassel.primitives.types.QVariant;
 import de.kuschku.libquassel.syncables.types.abstracts.ABacklogManager;
 import de.kuschku.util.observables.lists.ObservableComparableSortedList;
@@ -65,7 +69,7 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
         if (!initialized.contains(bufferId) || null == (last = storage.getUnfiltered(bufferId).last()))
             requestBacklogInitial(bufferId, amount);
         else {
-            requestBacklog(bufferId, -1, last.messageId, amount, 0);
+            requestBacklog(bufferId, -1, last.id, amount, 0);
         }
     }
 
@@ -76,7 +80,11 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
 
         waiting.add(id);
         waitingMax++;
-        requestBacklog(id, -1, -1, amount, 0);
+        Message lastMessageForBuffer = SQLite.select().from(Message.class).where(Message_Table.bufferInfo_id.eq(id)).orderBy(Message_Table.id, false).limit(1).querySingle();
+        if (lastMessageForBuffer != null)
+            requestBacklog(id, lastMessageForBuffer.id, -1, amount, 1);
+        else
+            requestBacklog(id, -1, -1, amount, 1);
     }
 
     @Override
@@ -88,6 +96,11 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
     public void _receiveBacklog(int id, int first, int last, int limit, int additional, @NonNull List<Message> messages) {
         assertNotNull(provider);
 
+        Log.d("DEBUG", "Received " + messages.size() + " messages out of a max of " + limit);
+
+        Message lastMessageForBuffer = SQLite.select().from(Message.class).where(Message_Table.bufferInfo_id.eq(id)).orderBy(Message_Table.id, false).limit(1).querySingle();
+        if (lastMessageForBuffer != null && messages.get(0).id > lastMessageForBuffer.id)
+            storage.clear(id);
         storage.insertMessages(id, messages.toArray(new Message[messages.size()]));
         if (messages.size() > 0 && !client.bufferManager().exists(messages.get(0).bufferInfo))
             client.bufferManager().createBuffer(messages.get(0).bufferInfo);
@@ -125,8 +138,8 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
 
         Set<Integer> buffers = new HashSet<>();
         for (Message message : messages) {
-            storage.insertMessages(message.bufferInfo.id(), message);
-            buffers.add(message.bufferInfo.id());
+            storage.insertMessages(message.bufferInfo.id, message);
+            buffers.add(message.bufferInfo.id);
         }
         for (int id : buffers) {
             provider.sendEvent(new BacklogReceivedEvent(id));
@@ -167,10 +180,13 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
     public void open(int bufferId) {
         assertNotNull(provider);
 
+        int oldBuffer = open();
         setOpen(bufferId);
         if (bufferId != -1 && client.bufferSyncer() != null)
             client.bufferSyncer().requestMarkBufferAsRead(bufferId);
         provider.sendEvent(new BufferChangeEvent());
+        if (oldBuffer != bufferId)
+            client.backlogStorage().markBufferUnused(oldBuffer);
     }
 
     @Override
@@ -181,7 +197,7 @@ public class BacklogManager extends ABacklogManager<BacklogManager> {
     @Override
     public void receiveBacklog(@NonNull Message msg) {
         storage.insertMessages(msg);
-        if (msg.bufferInfo.id() == openBuffer && openBuffer != -1)
+        if (msg.bufferInfo.id == openBuffer && openBuffer != -1)
             client.bufferSyncer().requestMarkBufferAsRead(openBuffer);
     }
 
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 1b6c15ec4..23176613b 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
@@ -177,8 +177,8 @@ public class BufferSyncer extends ABufferSyncer<BufferSyncer> {
             _setLastSeenMsg(buffer, -1);
             _setMarkerLine(buffer, -1);
         } else {
-            _setLastSeenMsg(buffer, lastMessage.messageId);
-            _setMarkerLine(buffer, lastMessage.messageId);
+            _setLastSeenMsg(buffer, lastMessage.id);
+            _setMarkerLine(buffer, lastMessage.id);
         }
     }
 
@@ -232,9 +232,9 @@ public class BufferSyncer extends ABufferSyncer<BufferSyncer> {
     }
 
     public void addActivity(@NonNull Message message) {
-        int lastSeenMsg = lastSeenMsg(message.bufferInfo.id());
-        if (message.messageId > lastSeenMsg) {
-            addActivity(message.bufferInfo.id(), message.type);
+        int lastSeenMsg = lastSeenMsg(message.bufferInfo.id);
+        if (message.id > lastSeenMsg) {
+            addActivity(message.bufferInfo.id, message.type);
         }
     }
 }
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 507797837..9ec26017d 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
@@ -141,10 +141,10 @@ public class BufferViewConfig extends ABufferViewConfig<BufferViewConfig> {
     @Override
     public DisplayType mayDisplay(Buffer buffer) {
         if (buffer != null &&
-                (allowedBufferTypes == 0 || (0 != (buffer.getInfo().type().id & allowedBufferTypes()))) &&
-                (networkId == 0 || (networkId == buffer.getInfo().networkId()))
+                (allowedBufferTypes == 0 || (0 != (buffer.getInfo().type.id & allowedBufferTypes()))) &&
+                (networkId == 0 || (networkId == buffer.getInfo().networkId))
                 ) {
-            int bufferid = buffer.getInfo().id();
+            int bufferid = buffer.getInfo().id;
             if (bufferIds.contains(bufferid) && !temporarilyRemovedBuffers.contains(bufferid) && !removedBuffers.contains(bufferid))
                 return DisplayType.ALWAYS;
             else if (temporarilyRemovedBuffers.contains(bufferid) && !removedBuffers.contains(bufferid))
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 8e61b521a..aa7e94d8c 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
@@ -23,6 +23,7 @@ package de.kuschku.libquassel.syncables.types.impl;
 
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutCompat;
 import android.util.SparseArray;
 
 import org.joda.time.DateTime;
@@ -57,6 +58,7 @@ public class IrcUser extends AIrcUser<IrcUser> {
     private String host;
     private String nick;
     private String realName;
+    private String account;
     private boolean away;
     private String awayMessage;
     private DateTime idleTime;
@@ -70,7 +72,7 @@ public class IrcUser extends AIrcUser<IrcUser> {
     private QNetwork network;
     private Set<Character> userModes;
 
-    public IrcUser(String server, String ircOperator, boolean away, int lastAwayMessage, DateTime idleTime, String whoisServiceReply, String suserHost, String nick, String realName, String awayMessage, DateTime loginTime, boolean encrypted, List<String> channels, String host, String userModes, String user) {
+    public IrcUser(String server, String ircOperator, boolean away, int lastAwayMessage, DateTime idleTime, String whoisServiceReply, String suserHost, String nick, String realName, String account, String awayMessage, DateTime loginTime, boolean encrypted, List<String> channels, String host, String userModes, String user) {
         this.server = server;
         this.ircOperator = ircOperator;
         this.away = away;
@@ -80,6 +82,7 @@ public class IrcUser extends AIrcUser<IrcUser> {
         this.suserHost = suserHost;
         this.nick = nick;
         this.realName = realName;
+        this.account = account;
         this.awayMessage = awayMessage;
         this.loginTime = loginTime;
         this.encrypted = encrypted;
@@ -118,6 +121,7 @@ public class IrcUser extends AIrcUser<IrcUser> {
                 null,
                 null,
                 null,
+                null,
                 false,
                 null,
                 host,
@@ -146,6 +150,11 @@ public class IrcUser extends AIrcUser<IrcUser> {
         return realName;
     }
 
+    @Override
+    public String account() {
+        return account;
+    }
+
     @Override
     public String hostmask() {
         return String.format("%s!%s@%s", nick(), user(), host());
@@ -280,6 +289,12 @@ public class IrcUser extends AIrcUser<IrcUser> {
         _update();
     }
 
+    @Override
+    public void _setAccount(String account) {
+        this.account = account;
+        _update();
+    }
+
     @Override
     public void _setAway(boolean away) {
         this.away = away;
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 7152d307a..d6310272f 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
@@ -42,6 +42,8 @@ public interface QIrcUser extends QObservable {
 
     String hostmask();
 
+    String account();
+
     boolean isAway();
 
     @Synced
@@ -101,6 +103,11 @@ public interface QIrcUser extends QObservable {
 
     void _setRealName(final String realName);
 
+    @Synced
+    void setAccount(final String account);
+
+    void _setAccount(final String account);
+
     void _setAway(final boolean away);
 
     @Synced
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasselDroidNG.java b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasselDroidNG.java
index d67ec36b3..3cc4a1d3e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasselDroidNG.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasselDroidNG.java
@@ -24,6 +24,11 @@ package de.kuschku.quasseldroid_ng;
 import android.app.Application;
 import android.content.Context;
 
+import com.raizlabs.android.dbflow.config.FlowConfig;
+import com.raizlabs.android.dbflow.config.FlowManager;
+
+import de.kuschku.libquassel.localtypes.orm.ConnectedDatabase;
+
 public class QuasselDroidNG extends Application {
 
     private static Context applicationContext;
@@ -36,5 +41,7 @@ public class QuasselDroidNG extends Application {
     public void onCreate() {
         super.onCreate();
         applicationContext = getApplicationContext();
+        FlowManager.init(new FlowConfig.Builder(this).build());
+        FlowManager.getDatabase(ConnectedDatabase.class).getWritableDatabase();
     }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/service/ClientBackgroundThread.java b/app/src/main/java/de/kuschku/quasseldroid_ng/service/ClientBackgroundThread.java
index 08db2fe2f..1bdc49cdc 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/service/ClientBackgroundThread.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/service/ClientBackgroundThread.java
@@ -33,7 +33,7 @@ import de.kuschku.libquassel.client.FeatureFlags;
 import de.kuschku.libquassel.events.ConnectionChangeEvent;
 import de.kuschku.libquassel.events.GeneralErrorEvent;
 import de.kuschku.libquassel.events.LoginRequireEvent;
-import de.kuschku.libquassel.localtypes.backlogstorage.MemoryBacklogStorage;
+import de.kuschku.libquassel.localtypes.backlogstorage.HybridBacklogStorage;
 import de.kuschku.libquassel.protocols.RemotePeer;
 import de.kuschku.quasseldroid_ng.ui.settings.Settings;
 import de.kuschku.util.CompatibilityUtils;
@@ -62,7 +62,7 @@ public class ClientBackgroundThread implements Runnable {
                 provider,
                 CLIENT_DATA,
                 new SQLiteCertificateManager(context),
-                new MemoryBacklogStorage(),
+                new HybridBacklogStorage(),
                 new SQLiteBufferMetaDataManager(context),
                 account.id.toString()
         );
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 d2913478a..5e2391e3a 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
@@ -83,7 +83,7 @@ public class ChannelDetailActivity extends BoundActivity {
         if (channel == null) return;
 
         if (channel.topic() == null) {
-            topic.setText(R.string.no_topic_set);
+            topic.setText(R.string.labelNoTopic);
             topic.setTextColor(context.themeUtil().res.colorForegroundSecondary);
             topic.setTypeface(Typeface.defaultFromStyle(Typeface.ITALIC));
         } else {
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 ed2679724..9a8cf337a 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
@@ -134,7 +134,7 @@ public class MainActivity extends BoundActivity {
         chatListAdapter = BufferViewConfigAdapter.of(context);
         chatListAdapter.setBufferClickListener(buffer -> {
             if (context.client() != null) {
-                context.client().backlogManager().open(buffer.getInfo().id());
+                context.client().backlogManager().open(buffer.getInfo().id);
                 if (drawerLayout != null)
                     drawerLayout.closeDrawer(GravityCompat.START);
             }
@@ -150,6 +150,7 @@ public class MainActivity extends BoundActivity {
         if (drawerLayout != null) {
             ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.material_drawer_open, R.string.material_drawer_close);
             toggle.syncState();
+            drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
         }
 
         replaceFragment(new LoadingFragment());
@@ -161,15 +162,16 @@ public class MainActivity extends BoundActivity {
     }
 
     @Override
-    protected void onPause() {
-        super.onPause();
+    protected void onStop() {
+        super.onStop();
         if (context.client() != null)
             context.client().backlogManager().setOpen(-1);
+        context.client().backlogStorage().markBufferUnused(context.client().backlogManager().open());
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
+    protected void onStart() {
+        super.onStart();
         if (context.client() != null)
             context.client().backlogManager().open(status.bufferId);
     }
@@ -266,6 +268,7 @@ public class MainActivity extends BoundActivity {
             int id = backlogManager.open();
             status.bufferId = id;
             updateBuffer(id);
+            chatListAdapter.setOpen(id);
         }
     }
 
@@ -331,6 +334,9 @@ public class MainActivity extends BoundActivity {
     }
 
     private void onConnected() {
+        if (drawerLayout != null)
+            drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
+
         context.client().backlogManager().open(status.bufferId);
         if (context.client().bufferViewManager() != null) {
             chatListSpinner.setAdapter(new BufferViewConfigSpinnerAdapter(context, context.client().bufferViewManager()));
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java
index 48ede6dd5..a0c4af4a2 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java
@@ -105,7 +105,7 @@ public class ChatMessageRenderer {
     @NonNull
     private CharSequence getBufferName(@NonNull Message message) {
         assertNotNull(context.client());
-        Buffer buffer = context.client().bufferManager().buffer(message.bufferInfo.id());
+        Buffer buffer = context.client().bufferManager().buffer(message.bufferInfo.id);
         assertNotNull(buffer);
         String name = buffer.getName();
         assertNotNull(name);
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
index a391374ae..1e1be5585 100644
--- 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
@@ -35,6 +35,7 @@ import java.lang.ref.WeakReference;
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import de.kuschku.libquassel.events.BufferChangeEvent;
 import de.kuschku.libquassel.localtypes.buffers.Buffer;
 import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewConfig;
 import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
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
index 8ec64bcd0..2723807f2 100644
--- 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
@@ -95,7 +95,7 @@ public class BufferViewHolder extends ChildViewHolder {
         status = buffer.getStatus();
         name.setText(buffer.getName());
         if (viewIntBinder != null) viewIntBinder.unbind();
-        viewIntBinder = new ViewIntBinder(context.client().bufferSyncer().activity(buffer.getInfo().id()));
+        viewIntBinder = new ViewIntBinder(context.client().bufferSyncer().activity(buffer.getInfo().id));
         viewIntBinder.bindTextColor(name, colorFromActivityStatus(buffer));
         setDescription(context.deserializer().formatString(getDescription(buffer)));
         setBadge(0);
@@ -103,9 +103,9 @@ public class BufferViewHolder extends ChildViewHolder {
 
         itemView.setBackground(background);
 
-        id = buffer.getInfo().id();
+        id = buffer.getInfo().id;
 
-        BufferInfo.Type type = buffer.getInfo().type();
+        BufferInfo.Type type = buffer.getInfo().type;
         setIcon(context, type, status);
         callback = new Observable.OnPropertyChangedCallback() {
             @Override
@@ -121,7 +121,7 @@ public class BufferViewHolder extends ChildViewHolder {
     @NonNull
     private Function<Integer, Integer> colorFromActivityStatus(Buffer buffer) {
         return activities -> {
-            int filters = context.client().backlogManager().filter(buffer.getInfo().id()).getFilters();
+            int filters = context.client().backlogManager().filter(buffer.getInfo().id).getFilters();
             activities = activities & ~filters;
             if (0 != ((activities & Message.Type.Plain.value) | (activities & Message.Type.Notice.value) | (activities & Message.Type.Action.value)))
                 return context.themeUtil().res.colorTintMessage;
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 2220c55db..e528083d0 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
@@ -39,20 +39,20 @@ public class NetworkItem implements ParentListItem {
     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()) {
+            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)
+                if (o1.getInfo().type == BufferInfo.Type.STATUS)
                     return -1;
-                else if (o2.getInfo().type() == BufferInfo.Type.STATUS)
+                else if (o2.getInfo().type == BufferInfo.Type.STATUS)
                     return 1;
-                else if (o1.getInfo().type() == BufferInfo.Type.CHANNEL)
+                else if (o1.getInfo().type == BufferInfo.Type.CHANNEL)
                     return -1;
-                else if (o2.getInfo().type() == BufferInfo.Type.CHANNEL)
+                else if (o2.getInfo().type == BufferInfo.Type.CHANNEL)
                     return 1;
-                else if (o1.getInfo().type() == BufferInfo.Type.GROUP)
+                else if (o1.getInfo().type == BufferInfo.Type.GROUP)
                     return -1;
-                else if (o2.getInfo().type() == BufferInfo.Type.GROUP)
+                else if (o2.getInfo().type == BufferInfo.Type.GROUP)
                     return 1;
                 else
                     return -1;
@@ -66,7 +66,7 @@ public class NetworkItem implements ParentListItem {
 
         @Override
         public boolean areItemsTheSame(Buffer item1, Buffer item2) {
-            return item1.getInfo().id() == item2.getInfo().id();
+            return item1.getInfo().id == item2.getInfo().id;
         }
     });
 
@@ -74,14 +74,14 @@ public class NetworkItem implements ParentListItem {
         this.network = network;
         for (int id : config.bufferList()) {
             Buffer buffer = context.client().bufferManager().buffer(id);
-            if (context.bufferDisplayTypes().contains(config.mayDisplay(buffer)) && buffer.getInfo().networkId() == network.networkId())
+            if (context.bufferDisplayTypes().contains(config.mayDisplay(buffer)) && buffer.getInfo().networkId == network.networkId())
                 buffers.add(buffer);
         }
         config.bufferIds().addCallback(new ElementCallback<Integer>() {
             @Override
             public void notifyItemInserted(Integer id) {
                 Buffer buffer = context.client().bufferManager().buffer(id);
-                if (context.bufferDisplayTypes().contains(config.mayDisplay(buffer)) && buffer.getInfo().networkId() == network.networkId())
+                if (context.bufferDisplayTypes().contains(config.mayDisplay(buffer)) && buffer.getInfo().networkId == network.networkId())
                     buffers.add(buffer);
             }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ScrollRefreshLayout.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ScrollRefreshLayout.java
new file mode 100644
index 000000000..cdaaf8338
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/util/ScrollRefreshLayout.java
@@ -0,0 +1,36 @@
+/*
+ * 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.content.Context;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.AttributeSet;
+
+public class ScrollRefreshLayout extends SwipeRefreshLayout {
+    public ScrollRefreshLayout(Context context) {
+        super(context);
+    }
+
+    public ScrollRefreshLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+}
diff --git a/app/src/main/java/de/kuschku/util/AndroidAssert.java b/app/src/main/java/de/kuschku/util/AndroidAssert.java
index 10d2b8829..055db4b0d 100644
--- a/app/src/main/java/de/kuschku/util/AndroidAssert.java
+++ b/app/src/main/java/de/kuschku/util/AndroidAssert.java
@@ -43,7 +43,7 @@ public class AndroidAssert extends Assert {
         }
     }
 
-    public static void assertTrue(String message, boolean condition) {
+    public static void assertTrue(@Nullable String message, boolean condition) {
         if (BuildConfig.DEBUG) {
             if (!condition) fail(message);
         }
@@ -79,7 +79,7 @@ public class AndroidAssert extends Assert {
         }
     }
 
-    public static void fail(String message) {
+    public static void fail(@Nullable String message) {
         if (BuildConfig.DEBUG) {
             throw new AssertionError(message);
         }
diff --git a/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java b/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java
index c7fefd73a..dd1f64cb9 100644
--- a/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java
+++ b/app/src/main/java/de/kuschku/util/irc/format/IrcFormatHelper.java
@@ -98,10 +98,10 @@ public class IrcFormatHelper {
         }
         Matcher channelMatcher = channelPattern.matcher(str);
         while (channelMatcher.find()) {
-            QIrcChannel channel = client.networkManager().network(bufferInfo.networkId()).ircChannel(channelMatcher.group());
+            QIrcChannel channel = client.networkManager().network(bufferInfo.networkId).ircChannel(channelMatcher.group());
             Buffer buffer = client.bufferManager().channel(channel);
             if (buffer != null)
-                spans.add(new FutureClickableSpan(new ChannelSpan(client, buffer.getInfo().id(), listener), channelMatcher.start(), channelMatcher.end()));
+                spans.add(new FutureClickableSpan(new ChannelSpan(client, buffer.getInfo().id, listener), channelMatcher.start(), channelMatcher.end()));
         }
         for (FutureClickableSpan span : spans) {
             str.setSpan(span.span, span.start, span.end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
diff --git a/app/src/main/java/de/kuschku/util/servicebound/BoundActivity.java b/app/src/main/java/de/kuschku/util/servicebound/BoundActivity.java
index 17a70f76d..1ca1e97be 100644
--- a/app/src/main/java/de/kuschku/util/servicebound/BoundActivity.java
+++ b/app/src/main/java/de/kuschku/util/servicebound/BoundActivity.java
@@ -69,8 +69,8 @@ public abstract class BoundActivity extends AppCompatActivity {
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
+    protected void onStart() {
+        super.onStart();
         ServiceHelper.connectToService(this, connection);
         if (themeId != AppTheme.themeFromString(context.settings().preferenceTheme.get()).themeId) {
             finish();
@@ -79,8 +79,8 @@ public abstract class BoundActivity extends AppCompatActivity {
     }
 
     @Override
-    protected void onPause() {
-        super.onPause();
+    protected void onStop() {
+        super.onStop();
         ServiceHelper.disconnect(this, connection);
     }
 
diff --git a/app/src/main/res/layout/fragment_chat.xml b/app/src/main/res/layout/fragment_chat.xml
index 5816e09be..b7053461b 100644
--- a/app/src/main/res/layout/fragment_chat.xml
+++ b/app/src/main/res/layout/fragment_chat.xml
@@ -34,7 +34,7 @@
     app:umanoShadowHeight="4dp"
     tools:showIn="@layout/activity_chat">
 
-    <android.support.v4.widget.SwipeRefreshLayout
+    <de.kuschku.quasseldroid_ng.ui.chat.util.ScrollRefreshLayout
         android:id="@+id/swipe_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
@@ -44,7 +44,7 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:clickable="true" />
-    </android.support.v4.widget.SwipeRefreshLayout>
+    </de.kuschku.quasseldroid_ng.ui.chat.util.ScrollRefreshLayout>
 
     <include layout="@layout/widget_slider" />
 
diff --git a/app/src/main/res/layout/slide.xml b/app/src/main/res/layout/slide.xml
index ec0910331..17b39ffe7 100644
--- a/app/src/main/res/layout/slide.xml
+++ b/app/src/main/res/layout/slide.xml
@@ -23,7 +23,8 @@
 <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:background="@color/md_light_cards" >
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -60,8 +61,7 @@
         <FrameLayout
             android:id="@+id/content_host"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:background="@color/md_light_cards" />
+            android:layout_height="wrap_content" />
 
     </LinearLayout>
 
diff --git a/app/src/main/res/layout/slide_account_core.xml b/app/src/main/res/layout/slide_account_core.xml
index de5791d49..678388484 100644
--- a/app/src/main/res/layout/slide_account_core.xml
+++ b/app/src/main/res/layout/slide_account_core.xml
@@ -30,7 +30,7 @@
     <android.support.design.widget.TextInputLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:hint="Hostname">
+        android:hint="@string/labelHostname">
         <android.support.v7.widget.AppCompatEditText
             android:id="@+id/host"
             android:layout_width="match_parent"
@@ -41,12 +41,13 @@
     <android.support.design.widget.TextInputLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:hint="Port">
+        android:hint="@string/labelPort">
         <android.support.v7.widget.AppCompatEditText
             android:id="@+id/port"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:inputType="number" />
+            android:inputType="number"
+            android:text="@string/defaultPort"/>
     </android.support.design.widget.TextInputLayout>
 
 </LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage.xml b/app/src/main/res/layout/widget_chatmessage.xml
index 9eefa4175..021b53088 100644
--- a/app/src/main/res/layout/widget_chatmessage.xml
+++ b/app/src/main/res/layout/widget_chatmessage.xml
@@ -22,7 +22,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
     android:clickable="true"
     android:gravity="top"
     android:orientation="horizontal"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e7d116012..ae9ebc859 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -30,13 +30,14 @@
 
     <!-- Editor UI -->
     <string name="placeholder">Write a message…</string>
+
     <string name="formatBold">Bold</string>
     <string name="formatItalic">Italic</string>
     <string name="formatUnderline">Underline</string>
     <string name="formatColor">Text Color</string>
     <string name="formatFill">Background Color</string>
 
-    <!-- Actions -->
+    <!-- Actions, Labels and Messages -->
     <string name="labelLogin">Login</string>
     <string name="labelCancel">Cancel</string>
     <string name="labelReconnect">Connect</string>
@@ -49,10 +50,14 @@
     <string name="labelPassword">Password</string>
     <string name="labelUsername">Username</string>
     <string name="labelHideEvents">Hide events</string>
-
+    <string name="labelNoTopic">No Topic Set</string>
+    <string name="labelUserOnHost">%1$s on %2$s</string>
     <string name="warningCertificate">Do you trust this certificate?</string>
 
-    <string name="labelUserOnHost">%1$s on %2$s</string>
+    <!-- Defaults -->
+    <string name="defaultPort" translatable="false">4242</string>
+
+    <!-- Slides -->
 
     <string name="slideAccountcoreTitle">The Core</string>
     <string name="slideAccountcoreDescription">First, please choose which server your core is hosted on – if you don’t know what a core is, click [here]</string>
@@ -66,6 +71,8 @@
     <string name="slideAccountnameTitle">Customize Account</string>
     <string name="slideAccountnameDescription">Give this account a name and icon</string>
 
+    <!-- Status -->
+
     <string name="statusConnecting">Connecting</string>
     <string name="statusHandshake">Logging in</string>
     <string name="statusInitData">Loading Networks and Channels</string>
@@ -73,5 +80,4 @@
     <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