From 263a2730b18712a0123f9b61f473e013cfcffd84 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sat, 2 Feb 2019 13:11:29 +0100
Subject: [PATCH] Cleaned up persistence code

---
 .../de/kuschku/quasseldroid/Quasseldroid.kt   |   7 +-
 .../quasseldroid/dagger/DatabaseModule.kt     |   4 +-
 .../quasseldroid/service/BacklogRequester.kt  |   6 +-
 .../service/QuasselNotificationBackend.kt     |  13 +-
 .../quasseldroid/service/QuasselService.kt    |   8 +-
 .../ssl/custom/QuasselCertificateManager.kt   |   4 +-
 .../ssl/custom/QuasselHostnameManager.kt      |   4 +-
 .../quasseldroid/ui/chat/ChatActivity.kt      |  19 +-
 .../chat/buffers/BufferViewConfigFragment.kt  |   4 +-
 .../ui/chat/messages/DisplayMessage.kt        |   4 +-
 .../ui/chat/messages/MessageAdapter.kt        |  24 +-
 .../ui/chat/messages/MessageListFragment.kt   |   9 +-
 .../ui/chat/messages/MessageRenderer.kt       |   4 +-
 .../chat/messages/QuasselMessageRenderer.kt   |   4 +-
 .../ui/clientsettings/whitelist/Whitelist.kt  |   7 +-
 .../whitelist/WhitelistCertificateAdapter.kt  |  28 +-
 .../whitelist/WhitelistFragment.kt            |   2 +-
 .../whitelist/WhitelistHostnameAdapter.kt     |  24 +-
 .../passwordchange/PasswordChangeFragment.kt  |   5 +-
 .../accounts/edit/AccountEditFragment.kt      |   5 +-
 .../accounts/selection/AccountAdapter.kt      |  10 +-
 .../selection/AccountSelectionSlide.kt        |   6 +-
 .../accounts/selection/AccountViewModel.kt    |   5 +-
 .../accounts/setup/AccountSetupActivity.kt    |   5 +-
 .../ui/setup/core/CoreSetupActivity.kt        |   6 +-
 .../quasseldroid/util/avatars/AvatarHelper.kt |   7 +-
 .../util/helper/AccountDaoHelper.kt           |   5 +-
 .../quasseldroid/util/AvatarHelperTest.kt     |   8 +-
 .../persistence/QuasselDatabase.kt            | 501 ------------------
 .../persistence/QuasselDatabaseHelpers.kt     |  91 ----
 .../persistence/dao/AccountDao.kt             |  51 ++
 .../persistence/dao/FilteredDao.kt            |  75 +++
 .../persistence/dao/LegacyAccountDao.kt       |  30 ++
 .../persistence/dao/MessageDao.kt             | 124 +++++
 .../persistence/dao/NotificationDao.kt        |  79 +++
 .../dao/SslHostnameWhitelistDao.kt            |  44 ++
 .../dao/SslValidityWhitelistDao.kt            |  44 ++
 .../persistence/{ => db}/AccountDatabase.kt   |  56 +-
 .../{ => db}/LegacyAccountDatabase.kt         |  32 +-
 .../persistence/db/QuasselDatabase.kt         | 172 ++++++
 .../persistence/models/Account.kt             |  38 ++
 .../persistence/models/Filtered.kt            |  48 ++
 .../persistence/models/LegacyAccount.kt       |  34 ++
 .../persistence/models/MessageData.kt         |  85 +++
 .../persistence/models/NotificationData.kt    | 110 ++++
 .../models/SslHostnameWhitelistEntry.kt       |  28 +
 .../models/SslValidityWhitelistEntry.kt       |  30 ++
 .../{ => util}/MessageTypeConverter.kt        |   2 +-
 .../{ => util}/QuasselBacklogStorage.kt       |  16 +-
 .../viewmodel/data/FormattedMessage.kt        |   4 +-
 50 files changed, 1158 insertions(+), 773 deletions(-)
 delete mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
 delete mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabaseHelpers.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/AccountDao.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/FilteredDao.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/LegacyAccountDao.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/MessageDao.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/NotificationDao.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslHostnameWhitelistDao.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslValidityWhitelistDao.kt
 rename persistence/src/main/java/de/kuschku/quasseldroid/persistence/{ => db}/AccountDatabase.kt (62%)
 rename persistence/src/main/java/de/kuschku/quasseldroid/persistence/{ => db}/LegacyAccountDatabase.kt (87%)
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/QuasselDatabase.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Account.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Filtered.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/LegacyAccount.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/MessageData.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/NotificationData.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslHostnameWhitelistEntry.kt
 create mode 100644 persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslValidityWhitelistEntry.kt
 rename persistence/src/main/java/de/kuschku/quasseldroid/persistence/{ => util}/MessageTypeConverter.kt (96%)
 rename persistence/src/main/java/de/kuschku/quasseldroid/persistence/{ => util}/QuasselBacklogStorage.kt (88%)

diff --git a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt
index a1c31e520..505d431ca 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt
@@ -27,8 +27,9 @@ import dagger.android.AndroidInjector
 import dagger.android.support.DaggerApplication
 import de.kuschku.malheur.CrashHandler
 import de.kuschku.quasseldroid.dagger.DaggerAppComponent
-import de.kuschku.quasseldroid.persistence.AccountDatabase
-import de.kuschku.quasseldroid.persistence.LegacyAccountDatabase
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.LegacyAccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.SettingsMigration
 import de.kuschku.quasseldroid.settings.SettingsMigrationManager
@@ -76,7 +77,7 @@ open class Quasseldroid : DaggerApplication() {
 
           val accountDatabase = AccountDatabase.Creator.init(this)
           accountDatabase.accounts().create(*accounts.map {
-            AccountDatabase.Account(
+            Account(
               id = it.id,
               host = it.host,
               port = it.port,
diff --git a/app/src/main/java/de/kuschku/quasseldroid/dagger/DatabaseModule.kt b/app/src/main/java/de/kuschku/quasseldroid/dagger/DatabaseModule.kt
index 8b1934aff..6adf83b3f 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/dagger/DatabaseModule.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/dagger/DatabaseModule.kt
@@ -22,8 +22,8 @@ package de.kuschku.quasseldroid.dagger
 import android.content.Context
 import dagger.Module
 import dagger.Provides
-import de.kuschku.quasseldroid.persistence.AccountDatabase
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
 
 @Module
 class DatabaseModule {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt b/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt
index 01e9893cd..41cfe8e37 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt
@@ -26,7 +26,11 @@ import de.kuschku.libquassel.session.ISession
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
 import de.kuschku.libquassel.util.helpers.value
-import de.kuschku.quasseldroid.persistence.*
+import de.kuschku.quasseldroid.persistence.dao.findFirstByBufferId
+import de.kuschku.quasseldroid.persistence.dao.get
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.util.QuasselBacklogStorage
 import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
 
 class BacklogRequester(
diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt
index c3b1ae0e3..c5876e6ba 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt
@@ -37,10 +37,11 @@ import de.kuschku.libquassel.util.irc.SenderColorUtil
 import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.GlideRequest
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
-import de.kuschku.quasseldroid.persistence.all
-import de.kuschku.quasseldroid.persistence.buffers
-import de.kuschku.quasseldroid.persistence.markRead
+import de.kuschku.quasseldroid.persistence.dao.all
+import de.kuschku.quasseldroid.persistence.dao.buffers
+import de.kuschku.quasseldroid.persistence.dao.markRead
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.NotificationData
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.settings.NotificationSettings
@@ -227,7 +228,7 @@ class QuasselNotificationBackend @Inject constructor(
     }.map {
       val network = session.network(it.bufferInfo.networkId)
       val me = network?.me()
-      QuasselDatabase.NotificationData.of(
+      NotificationData.of(
         messageId = it.messageId,
         creationTime = now,
         time = it.time,
@@ -254,7 +255,7 @@ class QuasselNotificationBackend @Inject constructor(
     if (show) {
       executor.schedule(
         {
-          results.map(QuasselDatabase.NotificationData::bufferId).distinct().forEach { buffer ->
+          results.map(NotificationData::bufferId).distinct().forEach { buffer ->
             this.showNotification(buffer)
           }
         },
diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
index a4fd817e3..f4e038cac 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
@@ -45,7 +45,13 @@ import de.kuschku.quasseldroid.BuildConfig
 import de.kuschku.quasseldroid.Keys
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.defaults.Defaults
-import de.kuschku.quasseldroid.persistence.*
+import de.kuschku.quasseldroid.persistence.dao.buffers
+import de.kuschku.quasseldroid.persistence.dao.clear
+import de.kuschku.quasseldroid.persistence.dao.markHidden
+import de.kuschku.quasseldroid.persistence.dao.markReadNormal
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.util.QuasselBacklogStorage
 import de.kuschku.quasseldroid.settings.ConnectionSettings
 import de.kuschku.quasseldroid.settings.NotificationSettings
 import de.kuschku.quasseldroid.settings.Settings
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselCertificateManager.kt b/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselCertificateManager.kt
index da115f23f..5832ba71b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselCertificateManager.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselCertificateManager.kt
@@ -19,13 +19,13 @@
 
 package de.kuschku.quasseldroid.ssl.custom
 
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.dao.SslValidityWhitelistDao
 import de.kuschku.quasseldroid.util.helper.isValid
 import de.kuschku.quasseldroid.util.helper.sha1Fingerprint
 import java.security.cert.X509Certificate
 
 class QuasselCertificateManager(
-  private val validityWhitelist: QuasselDatabase.SslValidityWhitelistDao
+  private val validityWhitelist: SslValidityWhitelistDao
 ) {
   fun isServerTrusted(chain: Array<out X509Certificate>?): Boolean {
     // Verify input conditions
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselHostnameManager.kt b/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselHostnameManager.kt
index 7472b5cdf..94eff4c6e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselHostnameManager.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ssl/custom/QuasselHostnameManager.kt
@@ -20,12 +20,12 @@
 package de.kuschku.quasseldroid.ssl.custom
 
 import de.kuschku.libquassel.connection.SocketAddress
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.dao.SslHostnameWhitelistDao
 import de.kuschku.quasseldroid.util.helper.sha1Fingerprint
 import java.security.cert.X509Certificate
 
 class QuasselHostnameManager(
-  private val hostnameWhitelist: QuasselDatabase.SslHostnameWhitelistDao
+  private val hostnameWhitelist: SslHostnameWhitelistDao
 ) {
   fun isValid(address: SocketAddress, chain: Array<out X509Certificate>): Boolean {
     val leafCertificate = chain.firstOrNull() ?: return false
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt
index cf52ec8cc..61c4db0e1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt
@@ -64,7 +64,14 @@ import de.kuschku.libquassel.util.helpers.value
 import de.kuschku.quasseldroid.Keys
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.defaults.DefaultNetworkServer
-import de.kuschku.quasseldroid.persistence.*
+import de.kuschku.quasseldroid.persistence.dao.clear
+import de.kuschku.quasseldroid.persistence.dao.get
+import de.kuschku.quasseldroid.persistence.dao.setFiltered
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.Filtered
+import de.kuschku.quasseldroid.persistence.models.SslHostnameWhitelistEntry
+import de.kuschku.quasseldroid.persistence.models.SslValidityWhitelistEntry
 import de.kuschku.quasseldroid.settings.AutoCompleteSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.settings.Settings
@@ -465,7 +472,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
                         .onPositive { _, _ ->
                           runInBackground {
                             database.validityWhitelist().save(
-                              QuasselDatabase.SslValidityWhitelistEntry(
+                              SslValidityWhitelistEntry(
                                 fingerprint = leafCertificate.sha1Fingerprint,
                                 ignoreDate = true
                               )
@@ -502,14 +509,14 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
                         .onPositive { _, _ ->
                           runInBackground {
                             database.validityWhitelist().save(
-                              QuasselDatabase.SslValidityWhitelistEntry(
+                              SslValidityWhitelistEntry(
                                 fingerprint = leafCertificate.sha1Fingerprint,
                                 ignoreDate = !leafCertificate.isValid
                               )
                             )
                             accountDatabase.accounts().findById(accountId)?.let {
                               database.hostnameWhitelist().save(
-                                QuasselDatabase.SslHostnameWhitelistEntry(
+                                SslHostnameWhitelistEntry(
                                   fingerprint = leafCertificate.sha1Fingerprint,
                                   hostname = it.host
                                 )
@@ -548,7 +555,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
                         .onPositive { _, _ ->
                           runInBackground {
                             database.hostnameWhitelist().save(
-                              QuasselDatabase.SslHostnameWhitelistEntry(
+                              SslHostnameWhitelistEntry(
                                 fingerprint = leafCertificate.sha1Fingerprint,
                                 hostname = it.address.host
                               )
@@ -892,7 +899,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
                   .fold(Message_Type.of()) { acc, i -> acc or i }
 
                 database.filtered().replace(
-                  QuasselDatabase.Filtered.of(accountId, buffer, newlyFiltered.value.toInt())
+                  Filtered.of(accountId, buffer, newlyFiltered.value.toInt())
                 )
               }
             }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
index 122e7c9a7..80ebec8a8 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
@@ -51,8 +51,8 @@ import de.kuschku.libquassel.util.helpers.mapOrElse
 import de.kuschku.libquassel.util.helpers.nullIf
 import de.kuschku.libquassel.util.helpers.value
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.AccountDatabase
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DisplayMessage.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DisplayMessage.kt
index 945d7b635..f1bb904e5 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DisplayMessage.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DisplayMessage.kt
@@ -22,10 +22,10 @@ package de.kuschku.quasseldroid.ui.chat.messages
 import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.MsgId
 import de.kuschku.libquassel.util.flag.hasFlag
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 
 data class DisplayMessage(
-  val content: QuasselDatabase.MessageData,
+  val content: MessageData,
   val hasDayChange: Boolean,
   val isFollowUp: Boolean,
   val isSelected: Boolean,
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt
index 95e31b796..bbee9923a 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt
@@ -35,7 +35,7 @@ import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.helper.getOrPut
 import de.kuschku.quasseldroid.util.helper.loadAvatars
@@ -58,9 +58,9 @@ class MessageAdapter @Inject constructor(
   private val movementMethod = BetterLinkMovementMethod.newInstance()
   private var clickListener: ((FormattedMessage) -> Unit)? = null
   private var longClickListener: ((FormattedMessage) -> Unit)? = null
-  private var doubleClickListener: ((QuasselDatabase.MessageData) -> Unit)? = null
-  private var senderIconClickListener: ((QuasselDatabase.MessageData) -> Unit)? = null
-  private var expansionListener: ((QuasselDatabase.MessageData) -> Unit)? = null
+  private var doubleClickListener: ((MessageData) -> Unit)? = null
+  private var senderIconClickListener: ((MessageData) -> Unit)? = null
+  private var expansionListener: ((MessageData) -> Unit)? = null
   private var urlLongClickListener: ((TextView, String) -> Boolean)? = null
 
   fun setOnClickListener(listener: ((FormattedMessage) -> Unit)?) {
@@ -71,15 +71,15 @@ class MessageAdapter @Inject constructor(
     this.longClickListener = listener
   }
 
-  fun setOnDoubleClickListener(listener: ((QuasselDatabase.MessageData) -> Unit)?) {
+  fun setOnDoubleClickListener(listener: ((MessageData) -> Unit)?) {
     this.doubleClickListener = listener
   }
 
-  fun setOnSenderIconClickListener(listener: ((QuasselDatabase.MessageData) -> Unit)?) {
+  fun setOnSenderIconClickListener(listener: ((MessageData) -> Unit)?) {
     this.senderIconClickListener = listener
   }
 
-  fun setOnExpansionListener(listener: ((QuasselDatabase.MessageData) -> Unit)?) {
+  fun setOnExpansionListener(listener: ((MessageData) -> Unit)?) {
     this.expansionListener = listener
   }
 
@@ -180,9 +180,9 @@ class MessageAdapter @Inject constructor(
     itemView: View,
     clickListener: ((FormattedMessage) -> Unit)? = null,
     longClickListener: ((FormattedMessage) -> Unit)? = null,
-    doubleClickListener: ((QuasselDatabase.MessageData) -> Unit)? = null,
-    senderIconClickListener: ((QuasselDatabase.MessageData) -> Unit)? = null,
-    expansionListener: ((QuasselDatabase.MessageData) -> Unit)? = null,
+    doubleClickListener: ((MessageData) -> Unit)? = null,
+    senderIconClickListener: ((MessageData) -> Unit)? = null,
+    expansionListener: ((MessageData) -> Unit)? = null,
     movementMethod: BetterLinkMovementMethod
   ) : RecyclerView.ViewHolder(itemView) {
     @BindView(R.id.daychange_container)
@@ -226,7 +226,7 @@ class MessageAdapter @Inject constructor(
     var combined: TextView? = null
 
     private var message: FormattedMessage? = null
-    private var original: QuasselDatabase.MessageData? = null
+    private var original: MessageData? = null
 
     private val localClickListener = View.OnClickListener {
       message?.let {
@@ -266,7 +266,7 @@ class MessageAdapter @Inject constructor(
       avatar?.setOnClickListener(localSenderIconClickListener)
     }
 
-    fun bind(message: FormattedMessage, original: QuasselDatabase.MessageData,
+    fun bind(message: FormattedMessage, original: MessageData,
              hasDayChange: Boolean, messageSettings: MessageSettings) {
       this.message = message
       this.original = original
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
index 6e6ab231d..d129255f3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
@@ -55,7 +55,10 @@ import de.kuschku.libquassel.util.helpers.value
 import de.kuschku.libquassel.util.irc.HostmaskHelper
 import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.*
+import de.kuschku.quasseldroid.persistence.dao.*
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 import de.kuschku.quasseldroid.service.BacklogRequester
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.AutoCompleteSettings
@@ -333,9 +336,9 @@ class MessageListFragment : ServiceBoundFragment() {
       }
     })
 
-    fun processMessages(list: List<QuasselDatabase.MessageData>, selected: Set<MsgId>,
+    fun processMessages(list: List<MessageData>, selected: Set<MsgId>,
                         expanded: Set<MsgId>, markerLine: MsgId?): List<DisplayMessage> {
-      var previous: QuasselDatabase.MessageData? = null
+      var previous: MessageData? = null
       var previousDate: ZonedDateTime? = null
       return list.mapReverse {
         val date = it.time.atZone(ZoneId.systemDefault()).truncatedTo(ChronoUnit.DAYS)
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt
index 811d18de4..989603fe3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.chat.messages
 import android.content.Context
 import androidx.annotation.LayoutRes
 import de.kuschku.libquassel.protocol.Message_Type
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage
 
 interface MessageRenderer {
@@ -34,7 +34,7 @@ interface MessageRenderer {
              isSelf: Boolean): Int
 
   fun bind(holder: MessageAdapter.QuasselMessageViewHolder, message: FormattedMessage,
-           original: QuasselDatabase.MessageData)
+           original: MessageData)
 
   fun render(context: Context, message: DisplayMessage): FormattedMessage
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
index 10de33940..c1a442171 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
@@ -37,7 +37,7 @@ import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.irc.HostmaskHelper
 import de.kuschku.libquassel.util.irc.SenderColorUtil
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.ColorContext
 import de.kuschku.quasseldroid.util.avatars.AvatarHelper
@@ -228,7 +228,7 @@ class QuasselMessageRenderer @Inject constructor(
   }
 
   override fun bind(holder: MessageAdapter.QuasselMessageViewHolder, message: FormattedMessage,
-                    original: QuasselDatabase.MessageData) =
+                    original: MessageData) =
     holder.bind(message,
                 original,
                 hasDayChange = message.hasDayChange,
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt
index b330c7fba..fff99e694 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt
@@ -19,9 +19,10 @@
 
 package de.kuschku.quasseldroid.ui.clientsettings.whitelist
 
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.SslHostnameWhitelistEntry
+import de.kuschku.quasseldroid.persistence.models.SslValidityWhitelistEntry
 
 data class Whitelist(
-  val certificates: List<QuasselDatabase.SslValidityWhitelistEntry>,
-  val hostnames: List<QuasselDatabase.SslHostnameWhitelistEntry>
+  val certificates: List<SslValidityWhitelistEntry>,
+  val hostnames: List<SslHostnameWhitelistEntry>
 )
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt
index 2e64005e9..6b8c16b3b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt
@@ -28,25 +28,25 @@ import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.SslValidityWhitelistEntry
 import de.kuschku.quasseldroid.util.helper.setTooltip
 import de.kuschku.quasseldroid.util.helper.visibleIf
 
 class WhitelistCertificateAdapter :
   RecyclerView.Adapter<WhitelistCertificateAdapter.WhitelistItemViewHolder>() {
-  private var clickListener: ((QuasselDatabase.SslValidityWhitelistEntry) -> Unit)? = null
-  private var updateListener: ((List<QuasselDatabase.SslValidityWhitelistEntry>) -> Unit)? = null
+  private var clickListener: ((SslValidityWhitelistEntry) -> Unit)? = null
+  private var updateListener: ((List<SslValidityWhitelistEntry>) -> Unit)? = null
 
-  fun setOnClickListener(listener: ((QuasselDatabase.SslValidityWhitelistEntry) -> Unit)?) {
+  fun setOnClickListener(listener: ((SslValidityWhitelistEntry) -> Unit)?) {
     clickListener = listener
   }
 
-  fun setOnUpdateListener(listener: ((List<QuasselDatabase.SslValidityWhitelistEntry>) -> Unit)?) {
+  fun setOnUpdateListener(listener: ((List<SslValidityWhitelistEntry>) -> Unit)?) {
     updateListener = listener
   }
 
-  private val data = mutableListOf<QuasselDatabase.SslValidityWhitelistEntry>()
-  var list: List<QuasselDatabase.SslValidityWhitelistEntry>
+  private val data = mutableListOf<SslValidityWhitelistEntry>()
+  var list: List<SslValidityWhitelistEntry>
     get() = data
     set(value) {
       val length = data.size
@@ -57,20 +57,20 @@ class WhitelistCertificateAdapter :
       updateListener?.invoke(list)
     }
 
-  fun add(item: QuasselDatabase.SslValidityWhitelistEntry) {
+  fun add(item: SslValidityWhitelistEntry) {
     val index = data.size
     data.add(item)
     notifyItemInserted(index)
     updateListener?.invoke(list)
   }
 
-  fun replace(index: Int, item: QuasselDatabase.SslValidityWhitelistEntry) {
+  fun replace(index: Int, item: SslValidityWhitelistEntry) {
     data[index] = item
     notifyItemChanged(index)
     updateListener?.invoke(list)
   }
 
-  fun indexOf(item: QuasselDatabase.SslValidityWhitelistEntry) = data.indexOf(item)
+  fun indexOf(item: SslValidityWhitelistEntry) = data.indexOf(item)
 
   fun remove(index: Int) {
     data.removeAt(index)
@@ -78,7 +78,7 @@ class WhitelistCertificateAdapter :
     updateListener?.invoke(list)
   }
 
-  fun remove(item: QuasselDatabase.SslValidityWhitelistEntry) = remove(indexOf(item))
+  fun remove(item: SslValidityWhitelistEntry) = remove(indexOf(item))
 
   override fun getItemCount() = data.size
 
@@ -95,7 +95,7 @@ class WhitelistCertificateAdapter :
 
   class WhitelistItemViewHolder(
     itemView: View,
-    clickListener: ((QuasselDatabase.SslValidityWhitelistEntry) -> Unit)?
+    clickListener: ((SslValidityWhitelistEntry) -> Unit)?
   ) : RecyclerView.ViewHolder(itemView) {
     @BindView(R.id.fingerprint)
     lateinit var fingerprint: TextView
@@ -106,7 +106,7 @@ class WhitelistCertificateAdapter :
     @BindView(R.id.action_delete)
     lateinit var delete: AppCompatImageButton
 
-    private var item: QuasselDatabase.SslValidityWhitelistEntry? = null
+    private var item: SslValidityWhitelistEntry? = null
 
     init {
       ButterKnife.bind(this, itemView)
@@ -118,7 +118,7 @@ class WhitelistCertificateAdapter :
       delete.setTooltip()
     }
 
-    fun bind(item: QuasselDatabase.SslValidityWhitelistEntry) {
+    fun bind(item: SslValidityWhitelistEntry) {
       this.item = item
       fingerprint.text = item.fingerprint
       ignoreDate.visibleIf(item.ignoreDate)
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt
index 82c89cade..354a8d979 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt
@@ -33,7 +33,7 @@ import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
 import de.kuschku.quasseldroid.util.helper.visibleIf
 import de.kuschku.quasseldroid.util.ui.settings.fragment.Changeable
 import de.kuschku.quasseldroid.util.ui.settings.fragment.Savable
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt
index 9f4810320..d90a89ff7 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt
@@ -28,19 +28,19 @@ import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.SslHostnameWhitelistEntry
 import de.kuschku.quasseldroid.util.helper.setTooltip
 
 class WhitelistHostnameAdapter :
   RecyclerView.Adapter<WhitelistHostnameAdapter.WhitelistItemViewHolder>() {
-  private var updateListener: ((List<QuasselDatabase.SslHostnameWhitelistEntry>) -> Unit)? = null
+  private var updateListener: ((List<SslHostnameWhitelistEntry>) -> Unit)? = null
 
-  fun setOnUpdateListener(listener: ((List<QuasselDatabase.SslHostnameWhitelistEntry>) -> Unit)?) {
+  fun setOnUpdateListener(listener: ((List<SslHostnameWhitelistEntry>) -> Unit)?) {
     updateListener = listener
   }
 
-  private val data = mutableListOf<QuasselDatabase.SslHostnameWhitelistEntry>()
-  var list: List<QuasselDatabase.SslHostnameWhitelistEntry>
+  private val data = mutableListOf<SslHostnameWhitelistEntry>()
+  var list: List<SslHostnameWhitelistEntry>
     get() = data
     set(value) {
       val length = data.size
@@ -51,20 +51,20 @@ class WhitelistHostnameAdapter :
       updateListener?.invoke(list)
     }
 
-  fun add(item: QuasselDatabase.SslHostnameWhitelistEntry) {
+  fun add(item: SslHostnameWhitelistEntry) {
     val index = data.size
     data.add(item)
     notifyItemInserted(index)
     updateListener?.invoke(list)
   }
 
-  fun replace(index: Int, item: QuasselDatabase.SslHostnameWhitelistEntry) {
+  fun replace(index: Int, item: SslHostnameWhitelistEntry) {
     data[index] = item
     notifyItemChanged(index)
     updateListener?.invoke(list)
   }
 
-  fun indexOf(item: QuasselDatabase.SslHostnameWhitelistEntry) = data.indexOf(item)
+  fun indexOf(item: SslHostnameWhitelistEntry) = data.indexOf(item)
 
   fun remove(index: Int) {
     data.removeAt(index)
@@ -72,7 +72,7 @@ class WhitelistHostnameAdapter :
     updateListener?.invoke(list)
   }
 
-  fun remove(item: QuasselDatabase.SslHostnameWhitelistEntry) = remove(indexOf(item))
+  fun remove(item: SslHostnameWhitelistEntry) = remove(indexOf(item))
 
   override fun getItemCount() = data.size
 
@@ -89,7 +89,7 @@ class WhitelistHostnameAdapter :
 
   class WhitelistItemViewHolder(
     itemView: View,
-    clickListener: ((QuasselDatabase.SslHostnameWhitelistEntry) -> Unit)?
+    clickListener: ((SslHostnameWhitelistEntry) -> Unit)?
   ) : RecyclerView.ViewHolder(itemView) {
     @BindView(R.id.hostname)
     lateinit var hostname: TextView
@@ -100,7 +100,7 @@ class WhitelistHostnameAdapter :
     @BindView(R.id.action_delete)
     lateinit var delete: AppCompatImageButton
 
-    private var item: QuasselDatabase.SslHostnameWhitelistEntry? = null
+    private var item: SslHostnameWhitelistEntry? = null
 
     init {
       ButterKnife.bind(this, itemView)
@@ -112,7 +112,7 @@ class WhitelistHostnameAdapter :
       delete.setTooltip()
     }
 
-    fun bind(item: QuasselDatabase.SslHostnameWhitelistEntry) {
+    fun bind(item: SslHostnameWhitelistEntry) {
       this.item = item
       hostname.text = item.hostname
       fingerprint.text = item.fingerprint
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/passwordchange/PasswordChangeFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/passwordchange/PasswordChangeFragment.kt
index a109cc96d..63c62f011 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/passwordchange/PasswordChangeFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/passwordchange/PasswordChangeFragment.kt
@@ -38,7 +38,8 @@ import de.kuschku.libquassel.util.helpers.mapMapNullable
 import de.kuschku.libquassel.util.helpers.mapSwitchMap
 import de.kuschku.libquassel.util.helpers.value
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.util.TextValidator
 import de.kuschku.quasseldroid.util.helper.toLiveData
 import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
@@ -76,7 +77,7 @@ class PasswordChangeFragment : ServiceBoundFragment() {
   @Inject
   lateinit var accountDatabase: AccountDatabase
 
-  private var waiting: AccountDatabase.Account? = null
+  private var waiting: Account? = null
 
   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                             savedInstanceState: Bundle?): View? {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditFragment.kt
index 3f6907436..2e1007e69 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditFragment.kt
@@ -35,7 +35,8 @@ import butterknife.ButterKnife
 import com.google.android.material.textfield.TextInputLayout
 import de.kuschku.quasseldroid.Keys
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.util.Patterns
 import de.kuschku.quasseldroid.util.TextValidator
 import de.kuschku.quasseldroid.util.helper.editCommit
@@ -77,7 +78,7 @@ class AccountEditFragment : SettingsFragment(), Changeable, Savable, Deletable {
   @Inject
   lateinit var database: AccountDatabase
 
-  private var account: AccountDatabase.Account? = null
+  private var account: Account? = null
   private var accountId: Long = -1L
 
   private lateinit var handlerThread: HandlerThread
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt
index b33801a6d..dc922c52d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt
@@ -35,12 +35,12 @@ import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.util.helper.zip
 
 class AccountAdapter(
   owner: LifecycleOwner,
-  liveData: LiveData<List<AccountDatabase.Account>>,
+  liveData: LiveData<List<Account>>,
   private val selectedItem: MutableLiveData<Pair<Long, Long>>
 ) : RecyclerView.Adapter<AccountAdapter.AccountViewHolder>() {
   private val actionListeners = mutableSetOf<(Long) -> Unit>()
@@ -77,7 +77,7 @@ class AccountAdapter(
   val selectedItemId
     get() = selectedItem.value?.second
 
-  private var list: List<Pair<Boolean, AccountDatabase.Account>> = emptyList()
+  private var list: List<Pair<Boolean, Account>> = emptyList()
 
   init {
     selectedItem.value = Pair(-1, -1)
@@ -88,7 +88,7 @@ class AccountAdapter(
       val selected = it?.second?.second ?: -1
 
       val oldList = this.list
-      val newList: List<Pair<Boolean, AccountDatabase.Account>> = list.orEmpty().map {
+      val newList: List<Pair<Boolean, Account>> = list.orEmpty().map {
         Pair(selected == it.id, it)
       }
       this.list = newList
@@ -220,7 +220,7 @@ class AccountAdapter(
         }
       }
 
-      fun bind(account: AccountDatabase.Account, selected: Boolean) {
+      fun bind(account: Account, selected: Boolean) {
         id = account.id
         accountName.text = account.name
         accountDescription.text = itemView.context.resources.getString(
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountSelectionSlide.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountSelectionSlide.kt
index 7bdd23ca8..d6aa6bd16 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountSelectionSlide.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountSelectionSlide.kt
@@ -32,7 +32,7 @@ import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.ui.setup.SlideFragment
 import de.kuschku.quasseldroid.ui.setup.accounts.edit.AccountEditActivity
 import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActivity.Companion.REQUEST_CREATE_FIRST
@@ -66,8 +66,8 @@ class AccountSelectionSlide : SlideFragment() {
                                savedInstanceState: Bundle?): View {
     val view = inflater.inflate(R.layout.setup_select_account, container, false)
     ButterKnife.bind(this, view)
-    val firstObserver = object : Observer<List<AccountDatabase.Account>?> {
-      override fun onChanged(t: List<AccountDatabase.Account>?) {
+    val firstObserver = object : Observer<List<Account>?> {
+      override fun onChanged(t: List<Account>?) {
         if (t?.isEmpty() != false)
           startActivityForResult(
             AccountSetupActivity.intent(requireContext()),
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountViewModel.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountViewModel.kt
index 49aa2ce2c..f268e8b8f 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountViewModel.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountViewModel.kt
@@ -23,12 +23,13 @@ import android.app.Application
 import androidx.lifecycle.AndroidViewModel
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 
 class AccountViewModel(application: Application) : AndroidViewModel(application) {
   private val database: AccountDatabase = AccountDatabase.Creator.init(
     getApplication()
   )
-  val accounts: LiveData<List<AccountDatabase.Account>> = database.accounts().all()
+  val accounts: LiveData<List<Account>> = database.accounts().all()
   val selectedItem = MutableLiveData<Pair<Long, Long>>()
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/setup/AccountSetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/setup/AccountSetupActivity.kt
index 9a89d2fa8..dab21b1e7 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/setup/AccountSetupActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/setup/AccountSetupActivity.kt
@@ -23,7 +23,8 @@ import android.app.Activity
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.db.AccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.ui.setup.SetupActivity
 import de.kuschku.quasseldroid.util.AndroidHandlerThread
 import org.threeten.bp.Instant
@@ -36,7 +37,7 @@ class AccountSetupActivity : SetupActivity() {
   lateinit var database: AccountDatabase
 
   override fun onDone(data: Bundle) {
-    val account = AccountDatabase.Account(
+    val account = Account(
       id = 0,
       host = data.getString("host", ""),
       port = data.getInt("port"),
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreSetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreSetupActivity.kt
index 571d6278b..b77644f34 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreSetupActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreSetupActivity.kt
@@ -29,7 +29,7 @@ import de.kuschku.libquassel.protocol.coresetup.CoreSetupData
 import de.kuschku.libquassel.protocol.message.HandshakeMessage
 import de.kuschku.libquassel.quassel.ExtendedFeature
 import de.kuschku.libquassel.util.helpers.value
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.ui.setup.ServiceBoundSetupActivity
 
 class CoreSetupActivity : ServiceBoundSetupActivity() {
@@ -84,13 +84,13 @@ class CoreSetupActivity : ServiceBoundSetupActivity() {
   companion object {
     fun launch(
       context: Context,
-      account: AccountDatabase.Account? = null,
+      account: Account? = null,
       data: CoreSetupData? = null
     ) = context.startActivity(intent(context, account, data))
 
     fun intent(
       context: Context,
-      account: AccountDatabase.Account? = null,
+      account: Account? = null,
       data: CoreSetupData? = null
     ) = Intent(context, CoreSetupActivity::class.java).apply {
       if (account != null) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt
index cd6c36f16..09b536b35 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt
@@ -22,7 +22,8 @@ package de.kuschku.quasseldroid.util.avatars
 import de.kuschku.libquassel.quassel.syncables.IrcUser
 import de.kuschku.libquassel.util.irc.HostmaskHelper
 import de.kuschku.libquassel.util.irc.IrcCaseMappers
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
+import de.kuschku.quasseldroid.persistence.models.NotificationData
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.info.user.IrcUserInfo
 import de.kuschku.quasseldroid.util.Patterns
@@ -50,11 +51,11 @@ object AvatarHelper {
       }
     ).flatten()
 
-  fun avatar(settings: MessageSettings, message: QuasselDatabase.NotificationData,
+  fun avatar(settings: MessageSettings, message: NotificationData,
              size: Int? = null) =
     avatar(settings, HostmaskHelper.user(message.sender), message.realName, message.avatarUrl, size)
 
-  fun avatar(settings: MessageSettings, message: QuasselDatabase.MessageData, size: Int? = null) =
+  fun avatar(settings: MessageSettings, message: MessageData, size: Int? = null) =
     avatar(settings, HostmaskHelper.user(message.sender), message.realName, message.avatarUrl, size)
 
   fun avatar(settings: MessageSettings, user: IrcUserItem, size: Int? = null) =
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/helper/AccountDaoHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/helper/AccountDaoHelper.kt
index 100d42672..27586108c 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/helper/AccountDaoHelper.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/helper/AccountDaoHelper.kt
@@ -19,9 +19,10 @@
 
 package de.kuschku.quasseldroid.util.helper
 
-import de.kuschku.quasseldroid.persistence.AccountDatabase
+import de.kuschku.quasseldroid.persistence.dao.AccountDao
+import de.kuschku.quasseldroid.persistence.models.Account
 
-fun AccountDatabase.AccountDao.new(vararg entities: AccountDatabase.Account) {
+fun AccountDao.new(vararg entities: Account) {
   val ids = create(*entities)
   for (i in 0 until entities.size) {
     entities[i].id = ids[i]
diff --git a/app/src/test/java/de/kuschku/quasseldroid/util/AvatarHelperTest.kt b/app/src/test/java/de/kuschku/quasseldroid/util/AvatarHelperTest.kt
index 0f2f6743d..33a3df319 100644
--- a/app/src/test/java/de/kuschku/quasseldroid/util/AvatarHelperTest.kt
+++ b/app/src/test/java/de/kuschku/quasseldroid/util/AvatarHelperTest.kt
@@ -20,7 +20,7 @@
 package de.kuschku.quasseldroid.util
 
 import de.kuschku.libquassel.protocol.*
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.avatars.AvatarHelper
 import de.kuschku.quasseldroid.viewmodel.data.Avatar
@@ -30,7 +30,7 @@ import org.threeten.bp.Instant
 class AvatarHelperTest {
   @Test
   fun testGravatarAvatars() {
-    val message = QuasselDatabase.MessageData.of(
+    val message = MessageData.of(
       messageId = MsgId(1),
       time = Instant.now(),
       type = Message_Type.of(Message_Type.Plain),
@@ -70,7 +70,7 @@ class AvatarHelperTest {
 
   @Test
   fun testIrcCloudAvatars() {
-    val message = QuasselDatabase.MessageData.of(
+    val message = MessageData.of(
       messageId = MsgId(1),
       time = Instant.now(),
       type = Message_Type.of(Message_Type.Plain),
@@ -110,7 +110,7 @@ class AvatarHelperTest {
 
   @Test
   fun testActualAvatars() {
-    val message = QuasselDatabase.MessageData.of(
+    val message = MessageData.of(
       messageId = MsgId(1),
       time = Instant.now(),
       type = Message_Type.of(Message_Type.Plain),
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
deleted file mode 100644
index fbe433e5e..000000000
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * Quasseldroid - Quassel client for Android
- *
- * Copyright (c) 2019 Janne Koschinski
- * Copyright (c) 2019 The Quassel Project
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3 as published
- * by the Free Software Foundation.
- *
- * 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/>.
- */
-@file:Suppress("NOTHING_TO_INLINE")
-package de.kuschku.quasseldroid.persistence
-
-import android.content.Context
-import androidx.lifecycle.LiveData
-import androidx.paging.DataSource
-import androidx.room.*
-import androidx.room.migration.Migration
-import androidx.sqlite.db.SupportSQLiteDatabase
-import de.kuschku.libquassel.protocol.*
-import de.kuschku.quasseldroid.persistence.QuasselDatabase.*
-import io.reactivex.Flowable
-import org.threeten.bp.Instant
-
-@Database(entities = [MessageData::class, Filtered::class, SslValidityWhitelistEntry::class, SslHostnameWhitelistEntry::class, NotificationData::class],
-          version = 19)
-@TypeConverters(MessageTypeConverter::class)
-abstract class QuasselDatabase : RoomDatabase() {
-  abstract fun message(): MessageDao
-  abstract fun filtered(): FilteredDao
-  abstract fun validityWhitelist(): SslValidityWhitelistDao
-  abstract fun hostnameWhitelist(): SslHostnameWhitelistDao
-  abstract fun notifications(): NotificationDao
-
-  @Entity(tableName = "message", indices = [Index("bufferId"), Index("ignored")])
-  data class MessageData(
-    @PrimaryKey
-    @ColumnInfo(name = "messageId")
-    var rawMessageId: MsgId_Type,
-    var time: Instant,
-    var type: Message_Types,
-    var flag: Message_Flags,
-    @ColumnInfo(name = "bufferId")
-    var rawBufferId: BufferId_Type,
-    @ColumnInfo(name = "networkId")
-    var rawNetworkId: NetworkId_Type,
-    var sender: String,
-    var senderPrefixes: String,
-    var realName: String,
-    var avatarUrl: String,
-    var content: String,
-    var ignored: Boolean
-  ) {
-    inline val messageId
-      get() = MsgId(rawMessageId)
-    inline val bufferId
-      get() = BufferId(rawBufferId)
-    inline val networkId
-      get() = NetworkId(rawNetworkId)
-
-    companion object {
-      inline fun of(
-        messageId: MsgId,
-        time: Instant,
-        type: Message_Types,
-        flag: Message_Flags,
-        bufferId: BufferId,
-        networkId: NetworkId,
-        sender: String,
-        senderPrefixes: String,
-        realName: String,
-        avatarUrl: String,
-        content: String,
-        ignored: Boolean
-      ) = MessageData(
-        messageId.id,
-        time,
-        type,
-        flag,
-        bufferId.id,
-        networkId.id,
-        sender,
-        senderPrefixes,
-        realName,
-        avatarUrl,
-        content,
-        ignored
-      )
-    }
-  }
-
-  @Dao
-  interface MessageDao {
-    @Query("SELECT * FROM message")
-    fun all(): List<MessageData>
-
-    @Query("SELECT DISTINCT bufferId FROM message")
-    fun _buffers(): List<BufferId_Type>
-
-    @Query("SELECT * FROM message WHERE messageId = :messageId")
-    fun find(messageId: MsgId_Type): MessageData?
-
-    @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC")
-    fun _findByBufferId(bufferId: BufferId_Type): List<MessageData>
-
-    @Query("SELECT * FROM message WHERE bufferId = :bufferId AND type & ~ :type > 0 AND ignored = 0 ORDER BY messageId DESC")
-    fun _findByBufferIdPaged(bufferId: BufferId_Type,
-                             type: Int): DataSource.Factory<Int, MessageData>
-
-    @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1")
-    fun _findLastByBufferId(bufferId: BufferId_Type): MessageData?
-
-    @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1")
-    fun _lastMsgId(bufferId: BufferId_Type): LiveData<MessageData>
-
-    @Query("SELECT messageId FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC LIMIT 1")
-    fun _firstMsgId(bufferId: BufferId_Type): Flowable<MsgId_Type>
-
-    @Query("SELECT messageId FROM message WHERE bufferId = :bufferId AND type & ~ :type > 0 AND ignored = 0 ORDER BY messageId ASC LIMIT 1")
-    fun _firstVisibleMsgId(bufferId: BufferId_Type, type: Int): MsgId_Type?
-
-    @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC LIMIT 1")
-    fun _findFirstByBufferId(bufferId: BufferId_Type): MessageData?
-
-    @Query("SELECT EXISTS(SELECT 1 FROM message WHERE bufferId = :bufferId AND type & ~ :type > 0 AND ignored = 0)")
-    fun _hasVisibleMessages(bufferId: BufferId_Type, type: Int): Boolean
-
-    @Insert(onConflict = OnConflictStrategy.REPLACE)
-    fun save(vararg entities: MessageData)
-
-    @Query("UPDATE message SET bufferId = :bufferId1 WHERE bufferId = :bufferId2")
-    fun _merge(bufferId1: BufferId_Type, bufferId2: BufferId_Type)
-
-    @Query("SELECT count(*) FROM message WHERE bufferId = :bufferId")
-    fun _bufferSize(bufferId: BufferId_Type): Int
-
-    @Query("DELETE FROM message")
-    fun clearMessages()
-
-    @Query("DELETE FROM message WHERE bufferId = :bufferId")
-    fun clearMessages(bufferId: BufferId_Type)
-
-    @Query(
-      "DELETE FROM message WHERE bufferId = :bufferId AND messageId >= :first AND messageId <= :last"
-    )
-    fun clearMessages(bufferId: BufferId_Type, first: MsgId_Type, last: MsgId_Type)
-  }
-
-  @Entity(tableName = "filtered", primaryKeys = ["accountId", "bufferId"])
-  data class Filtered(
-    var accountId: Long,
-    @ColumnInfo(name = "bufferId")
-    var rawBufferId: BufferId_Type,
-    var filtered: Int
-  ) {
-    inline val bufferId
-      get() = BufferId(rawBufferId)
-
-    companion object {
-      inline fun of(
-        accountId: Long,
-        bufferId: BufferId,
-        filtered: Int
-      ) = Filtered(
-        accountId,
-        bufferId.id,
-        filtered
-      )
-    }
-  }
-
-  @Dao
-  interface FilteredDao {
-    @Query("SELECT DISTINCT bufferId FROM filtered WHERE accountId = :accountId")
-    fun _buffers(accountId: Long): List<BufferId_Type>
-
-    @Insert(onConflict = OnConflictStrategy.REPLACE)
-    fun replace(vararg entities: Filtered)
-
-    @Query("UPDATE filtered SET filtered = :filtered WHERE accountId = :accountId AND bufferId = :bufferId")
-    fun _setFiltered(accountId: Long, bufferId: BufferId_Type, filtered: Int)
-
-    @Query("SELECT IFNULL(t.filtered, :defaultValue) FROM (SELECT filtered FROM filtered WHERE bufferId = :bufferId AND accountId = :accountId UNION SELECT NULL ORDER BY filtered DESC LIMIT 1) t")
-    fun _get(accountId: Long, bufferId: BufferId_Type, defaultValue: Int): Int
-
-    @Query("SELECT IFNULL(t.filtered, :defaultValue) FROM (SELECT filtered FROM filtered WHERE bufferId = :bufferId AND accountId = :accountId UNION SELECT NULL ORDER BY filtered DESC LIMIT 1) t")
-    fun _listen(accountId: Long, bufferId: BufferId_Type, defaultValue: Int): LiveData<Int>
-
-    @Query("SELECT * FROM filtered WHERE accountId = :accountId")
-    fun listen(accountId: Long): LiveData<List<Filtered>>
-
-    @Query("DELETE FROM filtered")
-    fun clear()
-
-    @Query("DELETE FROM filtered WHERE accountId = :accountId")
-    fun clear(accountId: Long)
-
-    @Query("DELETE FROM filtered WHERE bufferId = :bufferId AND accountId = :accountId")
-    fun _clear(accountId: Long, bufferId: BufferId_Type)
-  }
-
-  @Entity(tableName = "ssl_validity_whitelist")
-  data class SslValidityWhitelistEntry(
-    @PrimaryKey
-    var fingerprint: String,
-    var ignoreDate: Boolean
-  )
-
-  @Dao
-  interface SslValidityWhitelistDao {
-    @Insert(onConflict = OnConflictStrategy.REPLACE)
-    fun save(vararg entities: SslValidityWhitelistEntry)
-
-    @Query("SELECT * FROM ssl_validity_whitelist")
-    fun all(): List<SslValidityWhitelistEntry>
-
-    @Query("SELECT * FROM ssl_validity_whitelist WHERE fingerprint = :fingerprint")
-    fun find(fingerprint: String): SslValidityWhitelistEntry?
-
-    @Query("DELETE FROM ssl_validity_whitelist WHERE fingerprint = :fingerprint")
-    fun delete(fingerprint: String)
-
-    @Query("DELETE FROM ssl_validity_whitelist")
-    fun clear()
-  }
-
-  @Entity(tableName = "ssl_hostname_whitelist", primaryKeys = ["fingerprint", "hostname"])
-  data class SslHostnameWhitelistEntry(
-    var fingerprint: String,
-    var hostname: String
-  )
-
-  @Dao
-  interface SslHostnameWhitelistDao {
-    @Insert(onConflict = OnConflictStrategy.REPLACE)
-    fun save(vararg entities: SslHostnameWhitelistEntry)
-
-    @Query("SELECT * FROM ssl_hostname_whitelist")
-    fun all(): List<SslHostnameWhitelistEntry>
-
-    @Query("SELECT * FROM ssl_hostname_whitelist WHERE fingerprint = :fingerprint AND hostname = :hostname")
-    fun find(fingerprint: String, hostname: String): SslHostnameWhitelistEntry?
-
-    @Query("DELETE FROM ssl_hostname_whitelist WHERE fingerprint = :fingerprint AND hostname = :hostname")
-    fun delete(fingerprint: String, hostname: String)
-
-    @Query("DELETE FROM ssl_hostname_whitelist")
-    fun clear()
-  }
-
-  @Entity(tableName = "notification", indices = [Index("bufferId")])
-  data class NotificationData(
-    @PrimaryKey
-    @ColumnInfo(name = "messageId")
-    var rawMessageId: MsgId_Type,
-    var creationTime: Instant,
-    var time: Instant,
-    var type: Message_Types,
-    var flag: Message_Flags,
-    @ColumnInfo(name = "bufferId")
-    var rawBufferId: BufferId_Type,
-    var bufferName: String,
-    var bufferType: Buffer_Types,
-    @ColumnInfo(name = "networkId")
-    var rawNetworkId: NetworkId_Type,
-    var networkName: String,
-    var sender: String,
-    var senderPrefixes: String,
-    var realName: String,
-    var avatarUrl: String,
-    var content: String,
-    var ownNick: String,
-    var ownIdent: String,
-    var ownRealName: String,
-    var ownAvatarUrl: String,
-    var hidden: Boolean
-  ) {
-    inline val messageId
-      get() = MsgId(rawMessageId)
-
-    inline val bufferId
-      get() = BufferId(rawBufferId)
-
-    inline val networkId
-      get() = NetworkId(rawNetworkId)
-
-    companion object {
-      inline fun of(
-        messageId: MsgId,
-        creationTime: Instant,
-        time: Instant,
-        type: Message_Types,
-        flag: Message_Flags,
-        bufferId: BufferId,
-        bufferName: String,
-        bufferType: Buffer_Types,
-        networkId: NetworkId,
-        networkName: String,
-        sender: String,
-        senderPrefixes: String,
-        realName: String,
-        avatarUrl: String,
-        content: String,
-        ownNick: String,
-        ownIdent: String,
-        ownRealName: String,
-        ownAvatarUrl: String,
-        hidden: Boolean
-      ) = NotificationData(
-        messageId.id,
-        creationTime,
-        time,
-        type,
-        flag,
-        bufferId.id,
-        bufferName,
-        bufferType,
-        networkId.id,
-        networkName,
-        sender,
-        senderPrefixes,
-        realName,
-        avatarUrl,
-        content,
-        ownNick,
-        ownIdent,
-        ownRealName,
-        ownAvatarUrl,
-        hidden
-      )
-    }
-  }
-
-  @Dao
-  interface NotificationDao {
-    @Insert(onConflict = OnConflictStrategy.IGNORE)
-    fun save(vararg entities: NotificationData)
-
-    @Query("SELECT DISTINCT bufferId FROM notification")
-    fun _buffers(): List<BufferId_Type>
-
-    @Query("SELECT * FROM notification WHERE hidden = 0 ORDER BY time ASC")
-    fun all(): List<NotificationData>
-
-    @Query("SELECT * FROM notification WHERE bufferId = :bufferId AND hidden = 0 ORDER BY time ASC")
-    fun _all(bufferId: BufferId_Type): List<NotificationData>
-
-    @Query("UPDATE notification SET hidden = 1 WHERE bufferId = :bufferId AND messageId <= :messageId")
-    fun _markHidden(bufferId: BufferId_Type, messageId: MsgId_Type)
-
-    @Query("UPDATE notification SET hidden = 1 WHERE bufferId = :bufferId AND flag & 2 = 0")
-    fun _markHiddenNormal(bufferId: BufferId_Type)
-
-    @Query("DELETE FROM notification WHERE bufferId = :bufferId AND messageId <= :messageId")
-    fun _markRead(bufferId: BufferId_Type, messageId: MsgId_Type)
-
-    @Query("DELETE FROM notification WHERE bufferId = :bufferId AND flag & 2 = 0")
-    fun _markReadNormal(bufferId: BufferId_Type)
-
-    @Query("DELETE FROM notification")
-    fun clear()
-  }
-
-  object Creator {
-    private var database: QuasselDatabase? = null
-
-    // For Singleton instantiation
-    private val LOCK = Any()
-
-    fun init(context: Context): QuasselDatabase {
-      if (database == null) {
-        synchronized(LOCK) {
-          if (database == null) {
-            database = Room.databaseBuilder(
-              context.applicationContext,
-              QuasselDatabase::class.java, DATABASE_NAME
-            ).addMigrations(
-              object : Migration(2, 3) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL(
-                    "CREATE TABLE filtered(bufferId INTEGER, accountId INTEGER, filtered INTEGER, PRIMARY KEY(accountId, bufferId));"
-                  )
-                }
-              },
-              object : Migration(3, 4) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL(
-                    "ALTER TABLE message ADD followUp INT DEFAULT 0 NOT NULL;"
-                  )
-                }
-              },
-              object : Migration(4, 5) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("drop table message;")
-                  database.execSQL("create table message (messageId INTEGER not null primary key, time INTEGER not null, type INTEGER not null, flag INTEGER not null, bufferId INTEGER not null, sender TEXT not null, senderPrefixes TEXT not null, content TEXT not null);")
-                }
-              },
-              object : Migration(5, 6) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("drop table message;")
-                  database.execSQL("create table message (messageId INTEGER not null primary key, time INTEGER not null, type INTEGER not null, flag INTEGER not null, bufferId INTEGER not null, sender TEXT not null, senderPrefixes TEXT not null, realName TEXT not null, avatarUrl TEXT not null, content TEXT not null);")
-                }
-              },
-              object : Migration(6, 7) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("drop table message;")
-                  database.execSQL("create table message (messageId INTEGER not null primary key, time INTEGER not null, type INTEGER not null, flag INTEGER not null, bufferId INTEGER not null, sender TEXT not null, senderPrefixes TEXT not null, realName TEXT not null, avatarUrl TEXT not null, content TEXT not null, ignored INTEGER not null);")
-                }
-              },
-              object : Migration(7, 8) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("CREATE INDEX index_message_bufferId ON message(bufferId);")
-                  database.execSQL("CREATE INDEX index_message_ignored ON message(ignored);")
-                }
-              },
-              object : Migration(8, 9) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("create table ssl_exception (accountId INTEGER not null, certificateFingerprint TEXT not null, ignoreValidityDate INTEGER not null, primary key(accountId, certificateFingerprint));")
-                }
-              },
-              object : Migration(9, 10) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("drop table ssl_exception;")
-                  database.execSQL("create table ssl_exception (accountId INTEGER not null, hostName TEXT not null, certificateFingerprint TEXT not null, ignoreValidityDate INTEGER not null, primary key(accountId, hostName, certificateFingerprint));")
-                }
-              },
-              object : Migration(10, 11) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("drop table ssl_exception;")
-                  database.execSQL("create table ssl_exception (accountId INTEGER not null, certificateFingerprint TEXT not null, ignoreValidityDate INTEGER not null, primary key(accountId, certificateFingerprint));")
-                }
-              },
-              object : Migration(11, 12) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("drop table ssl_exception;")
-                  database.execSQL("create table ssl_validity_whitelist (fingerprint TEXT not null, ignoreDate INTEGER not null, primary key(fingerprint));")
-                  database.execSQL("create table ssl_hostname_whitelist (fingerprint TEXT not null, hostname TEXT not null, primary key(fingerprint, hostname));")
-                }
-              },
-              object : Migration(12, 13) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("drop table ssl_validity_whitelist;")
-                  database.execSQL("drop table ssl_hostname_whitelist;")
-                  database.execSQL("create table ssl_validity_whitelist (fingerprint TEXT not null, ignoreDate INTEGER not null, primary key(fingerprint));")
-                  database.execSQL("create table ssl_hostname_whitelist (fingerprint TEXT not null, hostname TEXT not null, primary key(fingerprint, hostname));")
-                }
-              },
-              object : Migration(13, 14) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("CREATE TABLE IF NOT EXISTS `notification` (`messageId` INTEGER NOT NULL, `time` INTEGER NOT NULL, `type` INTEGER NOT NULL, `flag` INTEGER NOT NULL, `bufferId` INTEGER NOT NULL, `bufferName` TEXT NOT NULL, `bufferType` INTEGER NOT NULL, `networkId` INTEGER NOT NULL, `sender` TEXT NOT NULL, `senderPrefixes` TEXT NOT NULL, `realName` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `content` TEXT NOT NULL, PRIMARY KEY(`messageId`));")
-                  database.execSQL("CREATE  INDEX `index_notification_bufferId` ON `notification` (`bufferId`);")
-                }
-              },
-              object : Migration(14, 15) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("ALTER TABLE message ADD networkId INT DEFAULT 0 NOT NULL;")
-                }
-              },
-              object : Migration(15, 16) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("ALTER TABLE `notification` ADD `creationTime` INT DEFAULT 0 NOT NULL;")
-                }
-              },
-              object : Migration(16, 17) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("ALTER TABLE `notification` ADD `ownNick` TEXT DEFAULT '' NOT NULL;")
-                  database.execSQL("ALTER TABLE `notification` ADD `ownIdent` TEXT DEFAULT '' NOT NULL;")
-                  database.execSQL("ALTER TABLE `notification` ADD `ownRealName` TEXT DEFAULT '' NOT NULL;")
-                  database.execSQL("ALTER TABLE `notification` ADD `ownAvatarUrl` TEXT DEFAULT '' NOT NULL;")
-                }
-              },
-              object : Migration(17, 18) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("ALTER TABLE `notification` ADD `hidden` INT DEFAULT 0 NOT NULL;")
-                }
-              },
-              object : Migration(18, 19) {
-                override fun migrate(database: SupportSQLiteDatabase) {
-                  database.execSQL("ALTER TABLE `notification` ADD `networkName` TEXT DEFAULT '' NOT NULL;")
-                }
-              }
-            ).build()
-          }
-        }
-      }
-      return database!!
-    }
-  }
-
-  companion object {
-    const val DATABASE_NAME = "persistence-clientData"
-  }
-}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabaseHelpers.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabaseHelpers.kt
deleted file mode 100644
index 952d4e7fd..000000000
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabaseHelpers.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Quasseldroid - Quassel client for Android
- *
- * Copyright (c) 2019 Janne Koschinski
- * Copyright (c) 2019 The Quassel Project
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3 as published
- * by the Free Software Foundation.
- *
- * 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/>.
- */
-@file:Suppress("NOTHING_TO_INLINE")
-package de.kuschku.quasseldroid.persistence
-
-import de.kuschku.libquassel.protocol.BufferId
-import de.kuschku.libquassel.protocol.MsgId
-
-inline fun QuasselDatabase.MessageDao.buffers() =
-  _buffers().map { BufferId(it) }
-
-inline fun QuasselDatabase.MessageDao.findByBufferId(bufferId: BufferId) =
-  _findByBufferId(bufferId.id)
-
-inline fun QuasselDatabase.MessageDao.findByBufferIdPaged(bufferId: BufferId, type: Int) =
-  _findByBufferIdPaged(bufferId.id, type)
-
-inline fun QuasselDatabase.MessageDao.findLastByBufferId(bufferId: BufferId) =
-  _findLastByBufferId(bufferId.id)
-
-inline fun QuasselDatabase.MessageDao.lastMsgId(bufferId: BufferId) =
-  _lastMsgId(bufferId.id)
-
-inline fun QuasselDatabase.MessageDao.firstMsgId(bufferId: BufferId) =
-  _firstMsgId(bufferId.id).map(::MsgId)
-
-inline fun QuasselDatabase.MessageDao.firstVisibleMsgId(bufferId: BufferId, type: Int) =
-  _firstVisibleMsgId(bufferId.id, type)?.let(::MsgId)
-
-inline fun QuasselDatabase.MessageDao.findFirstByBufferId(bufferId: BufferId) =
-  _findFirstByBufferId(bufferId.id)
-
-inline fun QuasselDatabase.MessageDao.hasVisibleMessages(bufferId: BufferId, type: Int) =
-  _hasVisibleMessages(bufferId.id, type)
-
-inline fun QuasselDatabase.MessageDao.merge(bufferId1: BufferId, bufferId2: BufferId) =
-  _merge(bufferId1.id, bufferId2.id)
-
-inline fun QuasselDatabase.MessageDao.bufferSize(bufferId: BufferId) =
-  _bufferSize(bufferId.id)
-
-inline fun QuasselDatabase.NotificationDao.buffers() =
-  _buffers().map(::BufferId)
-
-inline fun QuasselDatabase.NotificationDao.all(bufferId: BufferId) =
-  _all(bufferId.id)
-
-inline fun QuasselDatabase.NotificationDao.markHidden(bufferId: BufferId, messageId: MsgId) =
-  _markHidden(bufferId.id, messageId.id)
-
-inline fun QuasselDatabase.NotificationDao.markHiddenNormal(bufferId: BufferId) =
-  _markHiddenNormal(bufferId.id)
-
-inline fun QuasselDatabase.NotificationDao.markRead(bufferId: BufferId, messageId: MsgId) =
-  _markRead(bufferId.id, messageId.id)
-
-inline fun QuasselDatabase.NotificationDao.markReadNormal(bufferId: BufferId) =
-  _markReadNormal(bufferId.id)
-
-inline fun QuasselDatabase.FilteredDao.buffers(accountId: Long) =
-  _buffers(accountId).map(::BufferId)
-
-inline fun QuasselDatabase.FilteredDao.setFiltered(accountId: Long, bufferId: BufferId,
-                                                   filtered: Int) =
-  _setFiltered(accountId, bufferId.id, filtered)
-
-inline fun QuasselDatabase.FilteredDao.get(accountId: Long, bufferId: BufferId, defaultValue: Int) =
-  _get(accountId, bufferId.id, defaultValue)
-
-inline fun QuasselDatabase.FilteredDao.listen(accountId: Long, bufferId: BufferId,
-                                              defaultValue: Int) =
-  _listen(accountId, bufferId.id, defaultValue)
-
-inline fun QuasselDatabase.FilteredDao.clear(accountId: Long, bufferId: BufferId) =
-  _clear(accountId, bufferId.id)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/AccountDao.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/AccountDao.kt
new file mode 100644
index 000000000..0489423b5
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/AccountDao.kt
@@ -0,0 +1,51 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.dao
+
+import androidx.lifecycle.LiveData
+import androidx.room.*
+import de.kuschku.quasseldroid.persistence.models.Account
+
+@Dao
+interface AccountDao {
+  @Insert(onConflict = OnConflictStrategy.REPLACE)
+  fun save(vararg entities: Account)
+
+  @Insert(onConflict = OnConflictStrategy.IGNORE)
+  fun create(vararg entities: Account): Array<Long>
+
+  @Query("SELECT * FROM account WHERE id = :id")
+  fun findById(id: Long): Account?
+
+  @Query("SELECT * FROM account WHERE id = :id")
+  fun listen(id: Long): LiveData<Account?>
+
+  @Query("SELECT * FROM account ORDER BY lastUsed DESC")
+  fun all(): LiveData<List<Account>>
+
+  @Delete
+  fun delete(account: Account)
+
+  @Query("UPDATE account SET defaultFiltered = :defaultFiltered WHERE id = :id")
+  fun setFiltered(id: Long, defaultFiltered: Int)
+
+  @Query("DELETE FROM account")
+  fun clear()
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/FilteredDao.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/FilteredDao.kt
new file mode 100644
index 000000000..186346c19
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/FilteredDao.kt
@@ -0,0 +1,75 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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/>.
+ */
+@file:Suppress("NOTHING_TO_INLINE")
+
+package de.kuschku.quasseldroid.persistence.dao
+
+import androidx.lifecycle.LiveData
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import de.kuschku.libquassel.protocol.BufferId
+import de.kuschku.libquassel.protocol.BufferId_Type
+import de.kuschku.quasseldroid.persistence.models.Filtered
+
+@Dao
+interface FilteredDao {
+  @Query("SELECT DISTINCT bufferId FROM filtered WHERE accountId = :accountId")
+  fun _buffers(accountId: Long): List<BufferId_Type>
+
+  @Insert(onConflict = OnConflictStrategy.REPLACE)
+  fun replace(vararg entities: Filtered)
+
+  @Query("UPDATE filtered SET filtered = :filtered WHERE accountId = :accountId AND bufferId = :bufferId")
+  fun _setFiltered(accountId: Long, bufferId: BufferId_Type, filtered: Int)
+
+  @Query("SELECT IFNULL(t.filtered, :defaultValue) FROM (SELECT filtered FROM filtered WHERE bufferId = :bufferId AND accountId = :accountId UNION SELECT NULL ORDER BY filtered DESC LIMIT 1) t")
+  fun _get(accountId: Long, bufferId: BufferId_Type, defaultValue: Int): Int
+
+  @Query("SELECT IFNULL(t.filtered, :defaultValue) FROM (SELECT filtered FROM filtered WHERE bufferId = :bufferId AND accountId = :accountId UNION SELECT NULL ORDER BY filtered DESC LIMIT 1) t")
+  fun _listen(accountId: Long, bufferId: BufferId_Type, defaultValue: Int): LiveData<Int>
+
+  @Query("SELECT * FROM filtered WHERE accountId = :accountId")
+  fun listen(accountId: Long): LiveData<List<Filtered>>
+
+  @Query("DELETE FROM filtered")
+  fun clear()
+
+  @Query("DELETE FROM filtered WHERE accountId = :accountId")
+  fun clear(accountId: Long)
+
+  @Query("DELETE FROM filtered WHERE bufferId = :bufferId AND accountId = :accountId")
+  fun _clear(accountId: Long, bufferId: BufferId_Type)
+}
+
+inline fun FilteredDao.buffers(accountId: Long) =
+  _buffers(accountId).map(::BufferId)
+
+inline fun FilteredDao.setFiltered(accountId: Long, bufferId: BufferId, filtered: Int) =
+  _setFiltered(accountId, bufferId.id, filtered)
+
+inline fun FilteredDao.get(accountId: Long, bufferId: BufferId, defaultValue: Int) =
+  _get(accountId, bufferId.id, defaultValue)
+
+inline fun FilteredDao.listen(accountId: Long, bufferId: BufferId, defaultValue: Int) =
+  _listen(accountId, bufferId.id, defaultValue)
+
+inline fun FilteredDao.clear(accountId: Long, bufferId: BufferId) =
+  _clear(accountId, bufferId.id)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/LegacyAccountDao.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/LegacyAccountDao.kt
new file mode 100644
index 000000000..b1df8578b
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/LegacyAccountDao.kt
@@ -0,0 +1,30 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import de.kuschku.quasseldroid.persistence.models.LegacyAccount
+
+@Dao
+interface LegacyAccountDao {
+  @Query("SELECT * FROM account")
+  fun all(): List<LegacyAccount>
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/MessageDao.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/MessageDao.kt
new file mode 100644
index 000000000..9880dcf9d
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/MessageDao.kt
@@ -0,0 +1,124 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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/>.
+ */
+@file:Suppress("NOTHING_TO_INLINE")
+
+package de.kuschku.quasseldroid.persistence.dao
+
+import androidx.lifecycle.LiveData
+import androidx.paging.DataSource
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import de.kuschku.libquassel.protocol.BufferId
+import de.kuschku.libquassel.protocol.BufferId_Type
+import de.kuschku.libquassel.protocol.MsgId
+import de.kuschku.libquassel.protocol.MsgId_Type
+import de.kuschku.quasseldroid.persistence.models.MessageData
+import io.reactivex.Flowable
+
+@Dao
+interface MessageDao {
+  @Query("SELECT * FROM message")
+  fun all(): List<MessageData>
+
+  @Query("SELECT DISTINCT bufferId FROM message")
+  fun _buffers(): List<BufferId_Type>
+
+  @Query("SELECT * FROM message WHERE messageId = :messageId")
+  fun find(messageId: MsgId_Type): MessageData?
+
+  @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC")
+  fun _findByBufferId(bufferId: BufferId_Type): List<MessageData>
+
+  @Query("SELECT * FROM message WHERE bufferId = :bufferId AND type & ~ :type > 0 AND ignored = 0 ORDER BY messageId DESC")
+  fun _findByBufferIdPaged(bufferId: BufferId_Type,
+                           type: Int): DataSource.Factory<Int, MessageData>
+
+  @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1")
+  fun _findLastByBufferId(bufferId: BufferId_Type): MessageData?
+
+  @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1")
+  fun _lastMsgId(bufferId: BufferId_Type): LiveData<MessageData>
+
+  @Query("SELECT messageId FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC LIMIT 1")
+  fun _firstMsgId(bufferId: BufferId_Type): Flowable<MsgId_Type>
+
+  @Query("SELECT messageId FROM message WHERE bufferId = :bufferId AND type & ~ :type > 0 AND ignored = 0 ORDER BY messageId ASC LIMIT 1")
+  fun _firstVisibleMsgId(bufferId: BufferId_Type, type: Int): MsgId_Type?
+
+  @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC LIMIT 1")
+  fun _findFirstByBufferId(bufferId: BufferId_Type): MessageData?
+
+  @Query("SELECT EXISTS(SELECT 1 FROM message WHERE bufferId = :bufferId AND type & ~ :type > 0 AND ignored = 0)")
+  fun _hasVisibleMessages(bufferId: BufferId_Type, type: Int): Boolean
+
+  @Insert(onConflict = OnConflictStrategy.REPLACE)
+  fun save(vararg entities: MessageData)
+
+  @Query("UPDATE message SET bufferId = :bufferId1 WHERE bufferId = :bufferId2")
+  fun _merge(bufferId1: BufferId_Type, bufferId2: BufferId_Type)
+
+  @Query("SELECT count(*) FROM message WHERE bufferId = :bufferId")
+  fun _bufferSize(bufferId: BufferId_Type): Int
+
+  @Query("DELETE FROM message")
+  fun clearMessages()
+
+  @Query("DELETE FROM message WHERE bufferId = :bufferId")
+  fun clearMessages(bufferId: BufferId_Type)
+
+  @Query(
+    "DELETE FROM message WHERE bufferId = :bufferId AND messageId >= :first AND messageId <= :last"
+  )
+  fun clearMessages(bufferId: BufferId_Type, first: MsgId_Type, last: MsgId_Type)
+}
+
+inline fun MessageDao.buffers() =
+  _buffers().map { BufferId(it) }
+
+inline fun MessageDao.findByBufferId(bufferId: BufferId) =
+  _findByBufferId(bufferId.id)
+
+inline fun MessageDao.findByBufferIdPaged(bufferId: BufferId, type: Int) =
+  _findByBufferIdPaged(bufferId.id, type)
+
+inline fun MessageDao.findLastByBufferId(bufferId: BufferId) =
+  _findLastByBufferId(bufferId.id)
+
+inline fun MessageDao.lastMsgId(bufferId: BufferId) =
+  _lastMsgId(bufferId.id)
+
+inline fun MessageDao.firstMsgId(bufferId: BufferId) =
+  _firstMsgId(bufferId.id).map(::MsgId)
+
+inline fun MessageDao.firstVisibleMsgId(bufferId: BufferId, type: Int) =
+  _firstVisibleMsgId(bufferId.id, type)?.let(::MsgId)
+
+inline fun MessageDao.findFirstByBufferId(bufferId: BufferId) =
+  _findFirstByBufferId(bufferId.id)
+
+inline fun MessageDao.hasVisibleMessages(bufferId: BufferId, type: Int) =
+  _hasVisibleMessages(bufferId.id, type)
+
+inline fun MessageDao.merge(bufferId1: BufferId, bufferId2: BufferId) =
+  _merge(bufferId1.id, bufferId2.id)
+
+inline fun MessageDao.bufferSize(bufferId: BufferId) =
+  _bufferSize(bufferId.id)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/NotificationDao.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/NotificationDao.kt
new file mode 100644
index 000000000..53e1bf0f2
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/NotificationDao.kt
@@ -0,0 +1,79 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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/>.
+ */
+@file:Suppress("NOTHING_TO_INLINE")
+
+package de.kuschku.quasseldroid.persistence.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import de.kuschku.libquassel.protocol.BufferId
+import de.kuschku.libquassel.protocol.BufferId_Type
+import de.kuschku.libquassel.protocol.MsgId
+import de.kuschku.libquassel.protocol.MsgId_Type
+import de.kuschku.quasseldroid.persistence.models.NotificationData
+
+@Dao
+interface NotificationDao {
+  @Insert(onConflict = OnConflictStrategy.IGNORE)
+  fun save(vararg entities: NotificationData)
+
+  @Query("SELECT DISTINCT bufferId FROM notification")
+  fun _buffers(): List<BufferId_Type>
+
+  @Query("SELECT * FROM notification WHERE hidden = 0 ORDER BY time ASC")
+  fun all(): List<NotificationData>
+
+  @Query("SELECT * FROM notification WHERE bufferId = :bufferId AND hidden = 0 ORDER BY time ASC")
+  fun _all(bufferId: BufferId_Type): List<NotificationData>
+
+  @Query("UPDATE notification SET hidden = 1 WHERE bufferId = :bufferId AND messageId <= :messageId")
+  fun _markHidden(bufferId: BufferId_Type, messageId: MsgId_Type)
+
+  @Query("UPDATE notification SET hidden = 1 WHERE bufferId = :bufferId AND flag & 2 = 0")
+  fun _markHiddenNormal(bufferId: BufferId_Type)
+
+  @Query("DELETE FROM notification WHERE bufferId = :bufferId AND messageId <= :messageId")
+  fun _markRead(bufferId: BufferId_Type, messageId: MsgId_Type)
+
+  @Query("DELETE FROM notification WHERE bufferId = :bufferId AND flag & 2 = 0")
+  fun _markReadNormal(bufferId: BufferId_Type)
+
+  @Query("DELETE FROM notification")
+  fun clear()
+}
+
+inline fun NotificationDao.buffers() =
+  _buffers().map(::BufferId)
+
+inline fun NotificationDao.all(bufferId: BufferId) =
+  _all(bufferId.id)
+
+inline fun NotificationDao.markHidden(bufferId: BufferId, messageId: MsgId) =
+  _markHidden(bufferId.id, messageId.id)
+
+inline fun NotificationDao.markHiddenNormal(bufferId: BufferId) =
+  _markHiddenNormal(bufferId.id)
+
+inline fun NotificationDao.markRead(bufferId: BufferId, messageId: MsgId) =
+  _markRead(bufferId.id, messageId.id)
+
+inline fun NotificationDao.markReadNormal(bufferId: BufferId) =
+  _markReadNormal(bufferId.id)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslHostnameWhitelistDao.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslHostnameWhitelistDao.kt
new file mode 100644
index 000000000..23d0894d3
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslHostnameWhitelistDao.kt
@@ -0,0 +1,44 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import de.kuschku.quasseldroid.persistence.models.SslHostnameWhitelistEntry
+
+@Dao
+interface SslHostnameWhitelistDao {
+  @Insert(onConflict = OnConflictStrategy.REPLACE)
+  fun save(vararg entities: SslHostnameWhitelistEntry)
+
+  @Query("SELECT * FROM ssl_hostname_whitelist")
+  fun all(): List<SslHostnameWhitelistEntry>
+
+  @Query("SELECT * FROM ssl_hostname_whitelist WHERE fingerprint = :fingerprint AND hostname = :hostname")
+  fun find(fingerprint: String, hostname: String): SslHostnameWhitelistEntry?
+
+  @Query("DELETE FROM ssl_hostname_whitelist WHERE fingerprint = :fingerprint AND hostname = :hostname")
+  fun delete(fingerprint: String, hostname: String)
+
+  @Query("DELETE FROM ssl_hostname_whitelist")
+  fun clear()
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslValidityWhitelistDao.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslValidityWhitelistDao.kt
new file mode 100644
index 000000000..084225e2f
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/SslValidityWhitelistDao.kt
@@ -0,0 +1,44 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import de.kuschku.quasseldroid.persistence.models.SslValidityWhitelistEntry
+
+@Dao
+interface SslValidityWhitelistDao {
+  @Insert(onConflict = OnConflictStrategy.REPLACE)
+  fun save(vararg entities: SslValidityWhitelistEntry)
+
+  @Query("SELECT * FROM ssl_validity_whitelist")
+  fun all(): List<SslValidityWhitelistEntry>
+
+  @Query("SELECT * FROM ssl_validity_whitelist WHERE fingerprint = :fingerprint")
+  fun find(fingerprint: String): SslValidityWhitelistEntry?
+
+  @Query("DELETE FROM ssl_validity_whitelist WHERE fingerprint = :fingerprint")
+  fun delete(fingerprint: String)
+
+  @Query("DELETE FROM ssl_validity_whitelist")
+  fun clear()
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/AccountDatabase.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/AccountDatabase.kt
similarity index 62%
rename from persistence/src/main/java/de/kuschku/quasseldroid/persistence/AccountDatabase.kt
rename to persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/AccountDatabase.kt
index 2c1392a3b..24220ba8a 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/AccountDatabase.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/AccountDatabase.kt
@@ -17,60 +17,21 @@
  * with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid.persistence
+package de.kuschku.quasseldroid.persistence.db
 
 import android.content.Context
-import androidx.lifecycle.LiveData
-import androidx.room.*
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.room.migration.Migration
 import androidx.sqlite.db.SupportSQLiteDatabase
+import de.kuschku.quasseldroid.persistence.dao.AccountDao
+import de.kuschku.quasseldroid.persistence.models.Account
 
-@Database(entities = [(AccountDatabase.Account::class)], version = 4)
+@Database(entities = [(Account::class)], version = 4)
 abstract class AccountDatabase : RoomDatabase() {
   abstract fun accounts(): AccountDao
 
-  @Entity
-  data class Account(
-    @PrimaryKey(autoGenerate = true)
-    var id: Long,
-    var host: String,
-    var port: Int,
-    var requireSsl: Boolean,
-    var user: String,
-    var pass: String,
-    var name: String,
-    var lastUsed: Long,
-    var acceptedMissingFeatures: Boolean,
-    var defaultFiltered: Int
-  )
-
-  @Dao
-  interface AccountDao {
-    @Insert(onConflict = OnConflictStrategy.REPLACE)
-    fun save(vararg entities: AccountDatabase.Account)
-
-    @Insert(onConflict = OnConflictStrategy.IGNORE)
-    fun create(vararg entities: AccountDatabase.Account): Array<Long>
-
-    @Query("SELECT * FROM account WHERE id = :id")
-    fun findById(id: Long): AccountDatabase.Account?
-
-    @Query("SELECT * FROM account WHERE id = :id")
-    fun listen(id: Long): LiveData<AccountDatabase.Account?>
-
-    @Query("SELECT * FROM account ORDER BY lastUsed DESC")
-    fun all(): LiveData<List<Account>>
-
-    @Delete
-    fun delete(account: AccountDatabase.Account)
-
-    @Query("UPDATE account SET defaultFiltered = :defaultFiltered WHERE id = :id")
-    fun setFiltered(id: Long, defaultFiltered: Int)
-
-    @Query("DELETE FROM account")
-    fun clear()
-  }
-
   object Creator {
     private var database: AccountDatabase? = null
 
@@ -83,7 +44,8 @@ abstract class AccountDatabase : RoomDatabase() {
           if (database == null) {
             database = Room.databaseBuilder(
               context.applicationContext,
-              AccountDatabase::class.java, DATABASE_NAME
+              AccountDatabase::class.java,
+              DATABASE_NAME
             ).addMigrations(
               object : Migration(1, 2) {
                 override fun migrate(database: SupportSQLiteDatabase) {
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/LegacyAccountDatabase.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/LegacyAccountDatabase.kt
similarity index 87%
rename from persistence/src/main/java/de/kuschku/quasseldroid/persistence/LegacyAccountDatabase.kt
rename to persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/LegacyAccountDatabase.kt
index fe370442c..c92245adf 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/LegacyAccountDatabase.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/LegacyAccountDatabase.kt
@@ -17,33 +17,20 @@
  * with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid.persistence
+package de.kuschku.quasseldroid.persistence.db
 
 import android.content.Context
-import androidx.room.*
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.room.migration.Migration
 import androidx.sqlite.db.SupportSQLiteDatabase
+import de.kuschku.quasseldroid.persistence.dao.LegacyAccountDao
+import de.kuschku.quasseldroid.persistence.models.LegacyAccount
 
-@Database(entities = [(LegacyAccountDatabase.Account::class)], version = 4)
+@Database(entities = [(LegacyAccount::class)], version = 4)
 abstract class LegacyAccountDatabase : RoomDatabase() {
-  abstract fun accounts(): AccountDao
-
-  @Entity
-  data class Account(
-    @PrimaryKey
-    var id: Long,
-    var host: String,
-    var port: Int,
-    var user: String,
-    var pass: String,
-    var name: String
-  )
-
-  @Dao
-  interface AccountDao {
-    @Query("SELECT * FROM account")
-    fun all(): List<Account>
-  }
+  abstract fun accounts(): LegacyAccountDao
 
   object Creator {
     private var database: LegacyAccountDatabase? = null
@@ -57,7 +44,8 @@ abstract class LegacyAccountDatabase : RoomDatabase() {
           if (database == null) {
             database = Room.databaseBuilder(
               context.applicationContext,
-              LegacyAccountDatabase::class.java, DATABASE_NAME
+              LegacyAccountDatabase::class.java,
+              DATABASE_NAME
             ).addMigrations(
               object : Migration(0, 1) {
                 override fun migrate(database: SupportSQLiteDatabase) {
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/QuasselDatabase.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/QuasselDatabase.kt
new file mode 100644
index 000000000..e4d64c0ae
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/db/QuasselDatabase.kt
@@ -0,0 +1,172 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.db
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverters
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import de.kuschku.quasseldroid.persistence.dao.*
+import de.kuschku.quasseldroid.persistence.models.*
+import de.kuschku.quasseldroid.persistence.util.MessageTypeConverter
+
+@Database(entities = [MessageData::class, Filtered::class, SslValidityWhitelistEntry::class, SslHostnameWhitelistEntry::class, NotificationData::class],
+          version = 19)
+@TypeConverters(MessageTypeConverter::class)
+abstract class QuasselDatabase : RoomDatabase() {
+  abstract fun message(): MessageDao
+  abstract fun filtered(): FilteredDao
+  abstract fun validityWhitelist(): SslValidityWhitelistDao
+  abstract fun hostnameWhitelist(): SslHostnameWhitelistDao
+  abstract fun notifications(): NotificationDao
+
+  object Creator {
+    private var database: QuasselDatabase? = null
+
+    // For Singleton instantiation
+    private val LOCK = Any()
+
+    fun init(context: Context): QuasselDatabase {
+      if (database == null) {
+        synchronized(LOCK) {
+          if (database == null) {
+            database = Room.databaseBuilder(
+              context.applicationContext,
+              QuasselDatabase::class.java,
+              DATABASE_NAME
+            ).addMigrations(
+              object : Migration(2, 3) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL(
+                    "CREATE TABLE filtered(bufferId INTEGER, accountId INTEGER, filtered INTEGER, PRIMARY KEY(accountId, bufferId));"
+                  )
+                }
+              },
+              object : Migration(3, 4) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL(
+                    "ALTER TABLE message ADD followUp INT DEFAULT 0 NOT NULL;"
+                  )
+                }
+              },
+              object : Migration(4, 5) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("drop table message;")
+                  database.execSQL("create table message (messageId INTEGER not null primary key, time INTEGER not null, type INTEGER not null, flag INTEGER not null, bufferId INTEGER not null, sender TEXT not null, senderPrefixes TEXT not null, content TEXT not null);")
+                }
+              },
+              object : Migration(5, 6) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("drop table message;")
+                  database.execSQL("create table message (messageId INTEGER not null primary key, time INTEGER not null, type INTEGER not null, flag INTEGER not null, bufferId INTEGER not null, sender TEXT not null, senderPrefixes TEXT not null, realName TEXT not null, avatarUrl TEXT not null, content TEXT not null);")
+                }
+              },
+              object : Migration(6, 7) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("drop table message;")
+                  database.execSQL("create table message (messageId INTEGER not null primary key, time INTEGER not null, type INTEGER not null, flag INTEGER not null, bufferId INTEGER not null, sender TEXT not null, senderPrefixes TEXT not null, realName TEXT not null, avatarUrl TEXT not null, content TEXT not null, ignored INTEGER not null);")
+                }
+              },
+              object : Migration(7, 8) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("CREATE INDEX index_message_bufferId ON message(bufferId);")
+                  database.execSQL("CREATE INDEX index_message_ignored ON message(ignored);")
+                }
+              },
+              object : Migration(8, 9) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("create table ssl_exception (accountId INTEGER not null, certificateFingerprint TEXT not null, ignoreValidityDate INTEGER not null, primary key(accountId, certificateFingerprint));")
+                }
+              },
+              object : Migration(9, 10) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("drop table ssl_exception;")
+                  database.execSQL("create table ssl_exception (accountId INTEGER not null, hostName TEXT not null, certificateFingerprint TEXT not null, ignoreValidityDate INTEGER not null, primary key(accountId, hostName, certificateFingerprint));")
+                }
+              },
+              object : Migration(10, 11) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("drop table ssl_exception;")
+                  database.execSQL("create table ssl_exception (accountId INTEGER not null, certificateFingerprint TEXT not null, ignoreValidityDate INTEGER not null, primary key(accountId, certificateFingerprint));")
+                }
+              },
+              object : Migration(11, 12) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("drop table ssl_exception;")
+                  database.execSQL("create table ssl_validity_whitelist (fingerprint TEXT not null, ignoreDate INTEGER not null, primary key(fingerprint));")
+                  database.execSQL("create table ssl_hostname_whitelist (fingerprint TEXT not null, hostname TEXT not null, primary key(fingerprint, hostname));")
+                }
+              },
+              object : Migration(12, 13) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("drop table ssl_validity_whitelist;")
+                  database.execSQL("drop table ssl_hostname_whitelist;")
+                  database.execSQL("create table ssl_validity_whitelist (fingerprint TEXT not null, ignoreDate INTEGER not null, primary key(fingerprint));")
+                  database.execSQL("create table ssl_hostname_whitelist (fingerprint TEXT not null, hostname TEXT not null, primary key(fingerprint, hostname));")
+                }
+              },
+              object : Migration(13, 14) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("CREATE TABLE IF NOT EXISTS `notification` (`messageId` INTEGER NOT NULL, `time` INTEGER NOT NULL, `type` INTEGER NOT NULL, `flag` INTEGER NOT NULL, `bufferId` INTEGER NOT NULL, `bufferName` TEXT NOT NULL, `bufferType` INTEGER NOT NULL, `networkId` INTEGER NOT NULL, `sender` TEXT NOT NULL, `senderPrefixes` TEXT NOT NULL, `realName` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `content` TEXT NOT NULL, PRIMARY KEY(`messageId`));")
+                  database.execSQL("CREATE  INDEX `index_notification_bufferId` ON `notification` (`bufferId`);")
+                }
+              },
+              object : Migration(14, 15) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("ALTER TABLE message ADD networkId INT DEFAULT 0 NOT NULL;")
+                }
+              },
+              object : Migration(15, 16) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("ALTER TABLE `notification` ADD `creationTime` INT DEFAULT 0 NOT NULL;")
+                }
+              },
+              object : Migration(16, 17) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("ALTER TABLE `notification` ADD `ownNick` TEXT DEFAULT '' NOT NULL;")
+                  database.execSQL("ALTER TABLE `notification` ADD `ownIdent` TEXT DEFAULT '' NOT NULL;")
+                  database.execSQL("ALTER TABLE `notification` ADD `ownRealName` TEXT DEFAULT '' NOT NULL;")
+                  database.execSQL("ALTER TABLE `notification` ADD `ownAvatarUrl` TEXT DEFAULT '' NOT NULL;")
+                }
+              },
+              object : Migration(17, 18) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("ALTER TABLE `notification` ADD `hidden` INT DEFAULT 0 NOT NULL;")
+                }
+              },
+              object : Migration(18, 19) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("ALTER TABLE `notification` ADD `networkName` TEXT DEFAULT '' NOT NULL;")
+                }
+              }
+            ).build()
+          }
+        }
+      }
+      return database!!
+    }
+  }
+
+  companion object {
+    const val DATABASE_NAME = "persistence-clientData"
+  }
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Account.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Account.kt
new file mode 100644
index 000000000..e1c521e72
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Account.kt
@@ -0,0 +1,38 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.models
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "Account")
+data class Account(
+  @PrimaryKey(autoGenerate = true)
+  var id: Long,
+  var host: String,
+  var port: Int,
+  var requireSsl: Boolean,
+  var user: String,
+  var pass: String,
+  var name: String,
+  var lastUsed: Long,
+  var acceptedMissingFeatures: Boolean,
+  var defaultFiltered: Int
+)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Filtered.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Filtered.kt
new file mode 100644
index 000000000..3c6653dfa
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Filtered.kt
@@ -0,0 +1,48 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.models
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import de.kuschku.libquassel.protocol.BufferId
+import de.kuschku.libquassel.protocol.BufferId_Type
+
+@Entity(tableName = "filtered", primaryKeys = ["accountId", "bufferId"])
+data class Filtered(
+  var accountId: Long,
+  @ColumnInfo(name = "bufferId")
+  var rawBufferId: BufferId_Type,
+  var filtered: Int
+) {
+  inline val bufferId
+    get() = BufferId(rawBufferId)
+
+  companion object {
+    inline fun of(
+      accountId: Long,
+      bufferId: BufferId,
+      filtered: Int
+    ) = Filtered(
+      accountId,
+      bufferId.id,
+      filtered
+    )
+  }
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/LegacyAccount.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/LegacyAccount.kt
new file mode 100644
index 000000000..5f14ddd67
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/LegacyAccount.kt
@@ -0,0 +1,34 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.models
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "Account")
+data class LegacyAccount(
+  @PrimaryKey
+  var id: Long,
+  var host: String,
+  var port: Int,
+  var user: String,
+  var pass: String,
+  var name: String
+)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/MessageData.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/MessageData.kt
new file mode 100644
index 000000000..3233e80b6
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/MessageData.kt
@@ -0,0 +1,85 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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/>.
+ */
+@file:Suppress("NOTHING_TO_INLINE")
+
+package de.kuschku.quasseldroid.persistence.models
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import de.kuschku.libquassel.protocol.*
+import org.threeten.bp.Instant
+
+@Entity(tableName = "message", indices = [Index("bufferId"), Index("ignored")])
+data class MessageData(
+  @PrimaryKey
+  @ColumnInfo(name = "messageId")
+  var rawMessageId: MsgId_Type,
+  var time: Instant,
+  var type: Message_Types,
+  var flag: Message_Flags,
+  @ColumnInfo(name = "bufferId")
+  var rawBufferId: BufferId_Type,
+  @ColumnInfo(name = "networkId")
+  var rawNetworkId: NetworkId_Type,
+  var sender: String,
+  var senderPrefixes: String,
+  var realName: String,
+  var avatarUrl: String,
+  var content: String,
+  var ignored: Boolean
+) {
+  inline val messageId
+    get() = MsgId(rawMessageId)
+  inline val bufferId
+    get() = BufferId(rawBufferId)
+  inline val networkId
+    get() = NetworkId(rawNetworkId)
+
+  companion object {
+    inline fun of(
+      messageId: MsgId,
+      time: Instant,
+      type: Message_Types,
+      flag: Message_Flags,
+      bufferId: BufferId,
+      networkId: NetworkId,
+      sender: String,
+      senderPrefixes: String,
+      realName: String,
+      avatarUrl: String,
+      content: String,
+      ignored: Boolean
+    ) = MessageData(
+      messageId.id,
+      time,
+      type,
+      flag,
+      bufferId.id,
+      networkId.id,
+      sender,
+      senderPrefixes,
+      realName,
+      avatarUrl,
+      content,
+      ignored
+    )
+  }
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/NotificationData.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/NotificationData.kt
new file mode 100644
index 000000000..78e496330
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/NotificationData.kt
@@ -0,0 +1,110 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.models
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import de.kuschku.libquassel.protocol.*
+import org.threeten.bp.Instant
+
+@Entity(tableName = "notification", indices = [Index("bufferId")])
+data class NotificationData(
+  @PrimaryKey
+  @ColumnInfo(name = "messageId")
+  var rawMessageId: MsgId_Type,
+  var creationTime: Instant,
+  var time: Instant,
+  var type: Message_Types,
+  var flag: Message_Flags,
+  @ColumnInfo(name = "bufferId")
+  var rawBufferId: BufferId_Type,
+  var bufferName: String,
+  var bufferType: Buffer_Types,
+  @ColumnInfo(name = "networkId")
+  var rawNetworkId: NetworkId_Type,
+  var networkName: String,
+  var sender: String,
+  var senderPrefixes: String,
+  var realName: String,
+  var avatarUrl: String,
+  var content: String,
+  var ownNick: String,
+  var ownIdent: String,
+  var ownRealName: String,
+  var ownAvatarUrl: String,
+  var hidden: Boolean
+) {
+  inline val messageId
+    get() = MsgId(rawMessageId)
+
+  inline val bufferId
+    get() = BufferId(rawBufferId)
+
+  inline val networkId
+    get() = NetworkId(rawNetworkId)
+
+  companion object {
+    inline fun of(
+      messageId: MsgId,
+      creationTime: Instant,
+      time: Instant,
+      type: Message_Types,
+      flag: Message_Flags,
+      bufferId: BufferId,
+      bufferName: String,
+      bufferType: Buffer_Types,
+      networkId: NetworkId,
+      networkName: String,
+      sender: String,
+      senderPrefixes: String,
+      realName: String,
+      avatarUrl: String,
+      content: String,
+      ownNick: String,
+      ownIdent: String,
+      ownRealName: String,
+      ownAvatarUrl: String,
+      hidden: Boolean
+    ) = NotificationData(
+      messageId.id,
+      creationTime,
+      time,
+      type,
+      flag,
+      bufferId.id,
+      bufferName,
+      bufferType,
+      networkId.id,
+      networkName,
+      sender,
+      senderPrefixes,
+      realName,
+      avatarUrl,
+      content,
+      ownNick,
+      ownIdent,
+      ownRealName,
+      ownAvatarUrl,
+      hidden
+    )
+  }
+}
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslHostnameWhitelistEntry.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslHostnameWhitelistEntry.kt
new file mode 100644
index 000000000..8457af9ef
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslHostnameWhitelistEntry.kt
@@ -0,0 +1,28 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.models
+
+import androidx.room.Entity
+
+@Entity(tableName = "ssl_hostname_whitelist", primaryKeys = ["fingerprint", "hostname"])
+data class SslHostnameWhitelistEntry(
+  var fingerprint: String,
+  var hostname: String
+)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslValidityWhitelistEntry.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslValidityWhitelistEntry.kt
new file mode 100644
index 000000000..8da117292
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/SslValidityWhitelistEntry.kt
@@ -0,0 +1,30 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.persistence.models
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "ssl_validity_whitelist")
+data class SslValidityWhitelistEntry(
+  @PrimaryKey
+  var fingerprint: String,
+  var ignoreDate: Boolean
+)
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/MessageTypeConverter.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/MessageTypeConverter.kt
similarity index 96%
rename from persistence/src/main/java/de/kuschku/quasseldroid/persistence/MessageTypeConverter.kt
rename to persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/MessageTypeConverter.kt
index 2a678258e..6c97aa782 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/MessageTypeConverter.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/MessageTypeConverter.kt
@@ -17,7 +17,7 @@
  * with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid.persistence
+package de.kuschku.quasseldroid.persistence.util
 
 import androidx.room.TypeConverter
 import de.kuschku.libquassel.protocol.*
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselBacklogStorage.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/QuasselBacklogStorage.kt
similarity index 88%
rename from persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselBacklogStorage.kt
rename to persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/QuasselBacklogStorage.kt
index 777774a6e..60b813a7e 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselBacklogStorage.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/QuasselBacklogStorage.kt
@@ -17,7 +17,7 @@
  * with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid.persistence
+package de.kuschku.quasseldroid.persistence.util
 
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.Message
@@ -25,12 +25,16 @@ import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.quassel.syncables.IgnoreListManager
 import de.kuschku.libquassel.session.BacklogStorage
 import de.kuschku.libquassel.session.ISession
+import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 
 class QuasselBacklogStorage(private val db: QuasselDatabase) : BacklogStorage {
   override fun updateIgnoreRules(session: ISession) {
     db.message().save(
       *db.message().all().map {
-        it.copy(ignored = isIgnored(session, it))
+        it.copy(ignored = isIgnored(
+          session,
+          it))
       }.toTypedArray()
     )
   }
@@ -40,7 +44,7 @@ class QuasselBacklogStorage(private val db: QuasselDatabase) : BacklogStorage {
 
   override fun storeMessages(session: ISession, messages: Iterable<Message>) {
     db.message().save(*messages.map {
-      QuasselDatabase.MessageData.of(
+      MessageData.of(
         messageId = it.messageId,
         time = it.time,
         type = it.type,
@@ -52,7 +56,9 @@ class QuasselBacklogStorage(private val db: QuasselDatabase) : BacklogStorage {
         realName = it.realName,
         avatarUrl = it.avatarUrl,
         content = it.content,
-        ignored = isIgnored(session, it)
+        ignored = isIgnored(
+          session,
+          it)
       )
     }.toTypedArray())
   }
@@ -80,7 +86,7 @@ class QuasselBacklogStorage(private val db: QuasselDatabase) : BacklogStorage {
       ) != IgnoreListManager.StrictnessType.UnmatchedStrictness
     }
 
-    fun isIgnored(session: ISession, message: QuasselDatabase.MessageData): Boolean {
+    fun isIgnored(session: ISession, message: MessageData): Boolean {
       val bufferInfo = session.bufferSyncer.bufferInfo(message.bufferId)
       val bufferName = bufferInfo?.bufferName ?: ""
       val networkId = bufferInfo?.networkId ?: NetworkId(-1)
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt
index 73fad333b..b946cbc38 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt
@@ -20,10 +20,10 @@
 package de.kuschku.quasseldroid.viewmodel.data
 
 import android.graphics.drawable.Drawable
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.models.MessageData
 
 class FormattedMessage(
-  val original: QuasselDatabase.MessageData,
+  val original: MessageData,
   val time: CharSequence,
   val dayChange: CharSequence? = null,
   val name: CharSequence? = null,
-- 
GitLab