diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index bad294e320af8e5fee73f28fe58ce5c59f685b26..aab8c846f4f45607c74a4b7a142efda604ab3e71 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -38,7 +38,7 @@ android {
   }
 
   defaultConfig {
-    minSdkVersion(16)
+    minSdkVersion(20)
     targetSdkVersion(28)
 
     applicationId = "com.iskrembilen.quasseldroid"
@@ -69,7 +69,6 @@ android {
       isZipAlignEnabled = true
       isMinifyEnabled = true
       isShrinkResources = true
-      isUseProguard = false
 
       multiDexEnabled = false
 
@@ -99,38 +98,42 @@ android {
     isWarningsAsErrors = true
     setLintConfig(file("../lint.xml"))
   }
+
+  viewBinding {
+    isEnabled = true
+  }
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
 
   // App Compat
   implementation("com.google.android.material", "material", "1.1.0-alpha10")
 
   implementation("androidx.appcompat", "appcompat", "1.1.0")
-  implementation("androidx.browser", "browser", "1.2.0-alpha07")
+  implementation("androidx.browser", "browser", "1.2.0")
   implementation("androidx.cardview", "cardview", "1.0.0")
-  implementation("androidx.recyclerview", "recyclerview", "1.1.0-beta04")
-  implementation("androidx.swiperefreshlayout", "swiperefreshlayout", "1.1.0-alpha02")
-  implementation("androidx.preference", "preference", "1.0.0")
+  implementation("androidx.recyclerview", "recyclerview", "1.1.0")
+  implementation("androidx.swiperefreshlayout", "swiperefreshlayout", "1.1.0-beta01")
+  implementation("androidx.preference", "preference", "1.1.0")
   // Only needed for ringtone preference
   implementation("androidx.legacy", "legacy-preference-v14", "1.0.0")
-  implementation("androidx.constraintlayout", "constraintlayout", "2.0.0-beta1")
+  implementation("androidx.constraintlayout", "constraintlayout", "2.0.0-beta4")
 
-  withVersion("2.2.0-rc01") {
+  withVersion("2.2.5") {
     implementation("androidx.room", "room-runtime", version)
     kapt("androidx.room", "room-compiler", version)
     implementation("androidx.room", "room-rxjava2", version)
     testImplementation("androidx.room", "room-testing", version)
   }
-  withVersion("2.1.0") {
+  withVersion("2.2.0") {
     implementation("androidx.lifecycle", "lifecycle-extensions", version)
     implementation("androidx.lifecycle", "lifecycle-reactivestreams", version)
   }
   testImplementation("androidx.arch.core", "core-testing", "2.1.0")
   implementation(project(":lifecycle-ktx"))
 
-  implementation("androidx.paging", "paging-runtime", "2.1.0")
+  implementation("androidx.paging", "paging-runtime", "2.1.2")
 
   implementation("androidx.multidex", "multidex", "2.0.1")
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt
index a8a34ca2119a9c4df6200302b6be975188ea4842..612a8e22ad2d970342d2c077a9f65ed42e1093e3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -26,9 +26,11 @@ import de.kuschku.malheur.CrashHandler
 import de.kuschku.quasseldroid.BuildConfig
 import de.kuschku.quasseldroid.Quasseldroid
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.persistence.dao.create
 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.persistence.util.AccountId
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.SettingsMigration
 import de.kuschku.quasseldroid.settings.SettingsMigrationManager
@@ -53,8 +55,8 @@ class QuasseldroidReleaseDelegate(private val app: Quasseldroid) : QuasseldroidB
 
           val accountDatabase = AccountDatabase.Creator.init(app)
           accountDatabase.accounts().create(*accounts.map {
-            Account(
-              id = it.id,
+            Account.of(
+              id = AccountId(it.id),
               host = it.host,
               port = it.port,
               user = it.user,
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 9f33cdc3dafbe47d9a9ecdcc29d90e73408e440a..38215a15d45b7ce83e0a6f1ec96325e14199387e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -27,10 +27,12 @@ import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
 import de.kuschku.libquassel.util.helper.value
+import de.kuschku.quasseldroid.persistence.dao.findById
 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.AccountId
 import de.kuschku.quasseldroid.persistence.util.QuasselBacklogStorage
 import io.reactivex.Observable
 
@@ -39,7 +41,7 @@ class BacklogRequester(
   private val database: QuasselDatabase,
   private val accountDatabase: AccountDatabase
 ) {
-  fun loadMore(accountId: Long, buffer: BufferId, amount: Int, pageSize: Int,
+  fun loadMore(accountId: AccountId, buffer: BufferId, amount: Int, pageSize: Int,
                lastMessageId: MsgId? = null,
                untilAllVisible: Boolean = false,
                finishCallback: () -> Unit) {
@@ -49,10 +51,11 @@ class BacklogRequester(
     var missing = amount
     session.value?.orNull()?.let { session: ISession ->
       session.backlogManager.let {
-        val filtered = database.filtered().get(accountId,
-                                               buffer,
-                                               accountDatabase.accounts().findById(accountId)?.defaultFiltered
-                                               ?: 0)
+        val filtered = database.filtered().get(
+          accountId,
+          buffer,
+          accountDatabase.accounts().findById(accountId)?.defaultFiltered ?: 0
+        )
         it.requestBacklog(
           bufferId = buffer,
           last = lastMessageId
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 0b5a021a731f8da91f7928e4b8754d39c40bc21f..9ae2298125159bce4bb62ccc8d2531c35990cc91 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -48,12 +48,10 @@ 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.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.dao.*
 import de.kuschku.quasseldroid.persistence.db.AccountDatabase
 import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import de.kuschku.quasseldroid.persistence.util.QuasselBacklogStorage
 import de.kuschku.quasseldroid.settings.ConnectionSettings
 import de.kuschku.quasseldroid.settings.NotificationSettings
@@ -99,7 +97,7 @@ class QuasselService : DaggerLifecycleService(),
 
     val (accountId, reconnect) = this.sharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE) {
       Pair(
-        getLong(Keys.Status.selectedAccount, -1),
+        AccountId(getLong(Keys.Status.selectedAccount, -1)),
         getBoolean(Keys.Status.reconnect, false)
       )
     }
@@ -108,7 +106,7 @@ class QuasselService : DaggerLifecycleService(),
       this.reconnect = reconnect
 
       handlerService.backend {
-        val account = if (accountId != -1L && reconnect) {
+        val account = if (accountId.isValidId() && reconnect) {
           accountDatabase.accounts().findById(accountId)
         } else {
           null
@@ -129,7 +127,7 @@ class QuasselService : DaggerLifecycleService(),
           )
         }
       }
-    } else if (accountId == -1L || !reconnect) {
+    } else if (!accountId.isValidId() || !reconnect) {
       handlerService.backend {
         backendImplementation.disconnect(true)
         stopSelf()
@@ -137,12 +135,12 @@ class QuasselService : DaggerLifecycleService(),
     }
   }
 
-  private var accountId: Long = -1
+  private var accountId: AccountId = AccountId(-1)
     set(value) {
       field = value
       liveAccountId.onNext(value)
     }
-  private var liveAccountId = BehaviorSubject.createDefault(-1L)
+  private var liveAccountId = BehaviorSubject.createDefault(AccountId(-1L))
   private var reconnect: Boolean = false
 
   @Inject
@@ -169,13 +167,15 @@ class QuasselService : DaggerLifecycleService(),
     }
   }
 
-  override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+  override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
     val result = super.onStartCommand(intent, flags, startId)
     handleIntent(intent)
     return result
   }
 
-  private fun handleIntent(intent: Intent) {
+  private fun handleIntent(intent: Intent?) {
+    if (intent == null) return
+
     if (intent.getBooleanExtra("disconnect", false)) {
       sharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE) {
         editApply {
@@ -493,7 +493,7 @@ class QuasselService : DaggerLifecycleService(),
     super.onDestroy()
   }
 
-  override fun onBind(intent: Intent): QuasselBinder {
+  override fun onBind(intent: Intent?): QuasselBinder {
     super.onBind(intent)
     return QuasselBinder(asyncBackend)
   }
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 c3df0ced20f64ce99f30906957fee068d32546a1..5ee29db9ac3813498e54133b3dcd8a2742c9ea05 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -65,14 +65,13 @@ import de.kuschku.libquassel.util.helper.*
 import de.kuschku.quasseldroid.Keys
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.defaults.DefaultNetworkServer
-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.dao.*
 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.persistence.util.AccountId
 import de.kuschku.quasseldroid.settings.AutoCompleteSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.settings.NotificationSettings
@@ -163,7 +162,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
 
   private var chatlineFragment: ChatlineFragment? = null
 
-  private var connectedAccount = -1L
+  private var connectedAccount = AccountId(-1L)
 
   private var restoredDrawerState = false
 
@@ -182,12 +181,12 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
           chatViewModel.bufferId.onNext(BufferId(intent.getIntExtra(KEY_BUFFER_ID, -1)))
           chatViewModel.bufferOpened.onNext(Unit)
           if (intent.hasExtra(KEY_ACCOUNT_ID)) {
-            val accountId = intent.getLongExtra(ChatActivity.KEY_ACCOUNT_ID, -1)
+            val accountId = AccountId(intent.getLongExtra(KEY_ACCOUNT_ID, -1L))
             if (accountId != this.accountId) {
               resetAccount()
               connectToAccount(accountId)
               startedSelection = false
-              connectedAccount = -1L
+              connectedAccount = AccountId(-1L)
               checkConnection()
               recreate()
             }
@@ -848,18 +847,17 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
     editorBottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED
     chatlineFragment?.panelSlideListener?.let(editorBottomSheet::setBottomSheetCallback)
 
-    chatlineFragment?.historyBottomSheet?.setBottomSheetCallback(
-      object : BottomSheetBehavior.BottomSheetCallback() {
-        override fun onSlide(bottomSheet: View, slideOffset: Float) {
-          val opacity = (1.0f - slideOffset) / 2.0f
-          chatlineFragment?.editorContainer?.alpha = opacity
-        }
+    chatlineFragment?.historyBottomSheet?.bottomSheetCallback = object :
+      BottomSheetBehavior.BottomSheetCallback() {
+      override fun onSlide(bottomSheet: View, slideOffset: Float) {
+        val opacity = (1.0f - slideOffset) / 2.0f
+        chatlineFragment?.editorContainer?.alpha = opacity
+      }
 
-        override fun onStateChanged(bottomSheet: View, newState: Int) {
-          editorBottomSheet.allowDragging = newState == BottomSheetBehavior.STATE_HIDDEN
-        }
+      override fun onStateChanged(bottomSheet: View, newState: Int) {
+        editorBottomSheet.allowDragging = newState == BottomSheetBehavior.STATE_HIDDEN
       }
-    )
+    }
 
     combineLatest(modelHelper.allBuffers,
                   modelHelper.chat.chatToJoin).map { (buffers, chatToJoinOptional) ->
@@ -933,7 +931,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
     super.onSaveInstanceState(outState)
     chatViewModel.onSaveInstanceState(outState)
 
-    outState.putLong(KEY_CONNECTED_ACCOUNT, connectedAccount)
+    outState.putLong(KEY_CONNECTED_ACCOUNT, connectedAccount.id)
     outState.putBoolean(KEY_OPEN_DRAWER_START, drawerLayout.isDrawerOpen(GravityCompat.START))
     outState.putBoolean(KEY_OPEN_DRAWER_END, drawerLayout.isDrawerOpen(GravityCompat.END))
   }
@@ -944,7 +942,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
       chatViewModel.onRestoreInstanceState(savedInstanceState)
     }
 
-    connectedAccount = savedInstanceState?.getLong(KEY_CONNECTED_ACCOUNT, -1L) ?: -1L
+    connectedAccount = AccountId(savedInstanceState?.getLong(KEY_CONNECTED_ACCOUNT, -1L) ?: -1L)
 
     if (savedInstanceState?.getBoolean(KEY_OPEN_DRAWER_START) == true &&
         resources.getBoolean(R.bool.buffer_drawer_exists)) {
@@ -1108,7 +1106,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
 
     if (requestCode == REQUEST_SELECT_ACCOUNT) {
       startedSelection = false
-      connectedAccount = -1L
+      connectedAccount = AccountId(-1L)
 
       if (resultCode == Activity.RESULT_CANCELED) {
         finish()
@@ -1118,7 +1116,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
 
   private fun resetAccount() {
     startedSelection = true
-    connectedAccount = -1L
+    connectedAccount = AccountId(-1L)
     restoredDrawerState = false
     ChatActivity.launch(this, bufferId = BufferId.MAX_VALUE)
     chatViewModel.resetAccount()
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/add/NetworkAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/add/NetworkAdapter.kt
index 8cfcd6157ae9bcfcdd87d20faadf597d5a915b52..27ecf649507e7cfb654a07a7316086797f35cbfb 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/add/NetworkAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/add/NetworkAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.ui.chat.add
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.NetworkId
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -59,8 +55,7 @@ class NetworkAdapter : RecyclerSpinnerAdapter<NetworkAdapter.NetworkViewHolder>(
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
-    return NetworkViewHolder(view)
+    return NetworkViewHolder(WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false))
   }
 
   fun indexOf(id: NetworkId): Int? {
@@ -76,17 +71,11 @@ class NetworkAdapter : RecyclerSpinnerAdapter<NetworkAdapter.NetworkViewHolder>(
   override fun getItemId(position: Int) = getItem(position)?.id?.id?.toLong() ?: 0L
   override fun hasStableIds() = true
   override fun getCount() = data.size
-  class NetworkViewHolder(itemView: View) :
-    RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class NetworkViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(network: NetworkItem) {
-      text.text = network.name
+      binding.text1.text = network.name
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveFragment.kt
index 51871d359da83065f87faa631f86efdc981c7d01..2178edf34702d20f866e1531f8e3b0cb1a2ba45d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveFragment.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -33,6 +33,8 @@ import de.kuschku.libquassel.util.helper.combineLatest
 import de.kuschku.libquassel.util.helper.safeValue
 import de.kuschku.libquassel.util.helper.value
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.persistence.dao.listenDefaultFiltered
+import de.kuschku.quasseldroid.persistence.dao.listenRx
 import de.kuschku.quasseldroid.persistence.db.AccountDatabase
 import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
 import de.kuschku.quasseldroid.persistence.models.Filtered
@@ -164,11 +166,11 @@ class ArchiveFragment : ServiceBoundFragment() {
           content = getString(R.string.label_permanently_archived_empty)
         ))
       }
-    }.toLiveData().observe(this, Observer { processedList ->
+    }.toLiveData().observe(viewLifecycleOwner, Observer { processedList ->
       listAdapter.submitList(processedList)
     })
 
-    modelHelper.selectedBuffer.toLiveData().observe(this, Observer { buffer ->
+    modelHelper.selectedBuffer.toLiveData().observe(viewLifecycleOwner, Observer { buffer ->
       actionMode?.let {
         BufferContextPresenter.present(it, buffer)
       }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveListAdapter.kt
index 96ec44e92f18971cafe442f87fca8898847e7378..eba0b698ea57c2457bd73e2daea3d4d36fd49e85 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/archive/ArchiveListAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -24,17 +24,17 @@ import android.view.LayoutInflater
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.helper.safeValue
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetArchivePlaceholderBinding
+import de.kuschku.quasseldroid.databinding.WidgetBufferBinding
+import de.kuschku.quasseldroid.databinding.WidgetHeaderBinding
+import de.kuschku.quasseldroid.databinding.WidgetNetworkBinding
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.helper.*
 import de.kuschku.quasseldroid.util.lists.ListAdapter
@@ -112,45 +112,32 @@ class ArchiveListAdapter(
     val viewType = ViewType(viewType.toUInt())
     return when (viewType.type) {
       ArchiveListItem.Type.HEADER      -> ArchiveViewHolder.HeaderViewHolder(
-        LayoutInflater.from(parent.context).inflate(
-          R.layout.widget_header, parent, false
-        )
+        WidgetHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
       )
       ArchiveListItem.Type.PLACEHOLDER -> ArchiveViewHolder.PlaceholderViewHolder(
-        LayoutInflater.from(parent.context).inflate(
-          R.layout.widget_archive_placeholder, parent, false
-        )
+        WidgetArchivePlaceholderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
       )
       ArchiveListItem.Type.BUFFER      -> when (viewType.bufferType?.enabledValues()?.firstOrNull()) {
         BufferInfo.Type.ChannelBuffer -> ArchiveViewHolder.BufferViewHolder.ChannelBuffer(
-          LayoutInflater.from(parent.context).inflate(
-            R.layout.widget_buffer, parent, false
-          ),
+          WidgetBufferBinding.inflate(LayoutInflater.from(parent.context), parent, false),
           clickListener = clickListener,
           longClickListener = longClickListener,
           dragListener = dragListener
         )
         BufferInfo.Type.QueryBuffer   -> ArchiveViewHolder.BufferViewHolder.QueryBuffer(
-          LayoutInflater.from(parent.context).inflate(
-            if (viewType.bufferStatus == BufferStatus.AWAY) R.layout.widget_buffer_away
-            else R.layout.widget_buffer, parent, false
-          ),
+          WidgetBufferBinding.inflate(LayoutInflater.from(parent.context), parent, false),
           clickListener = clickListener,
           longClickListener = longClickListener,
           dragListener = dragListener
         )
         BufferInfo.Type.GroupBuffer   -> ArchiveViewHolder.BufferViewHolder.GroupBuffer(
-          LayoutInflater.from(parent.context).inflate(
-            R.layout.widget_buffer, parent, false
-          ),
+          WidgetBufferBinding.inflate(LayoutInflater.from(parent.context), parent, false),
           clickListener = clickListener,
           longClickListener = longClickListener,
           dragListener = dragListener
         )
         BufferInfo.Type.StatusBuffer  -> ArchiveViewHolder.BufferViewHolder.StatusBuffer(
-          LayoutInflater.from(parent.context).inflate(
-            R.layout.widget_network, parent, false
-          ),
+          WidgetNetworkBinding.inflate(LayoutInflater.from(parent.context), parent, false),
           clickListener = clickListener,
           longClickListener = longClickListener,
           expansionListener = ::expandListener
@@ -204,36 +191,19 @@ class ArchiveListAdapter(
 
   sealed class ArchiveViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
     class HeaderViewHolder(
-      itemView: View
-    ) : ArchiveViewHolder(itemView) {
-      @BindView(R.id.title)
-      lateinit var title: TextView
-
-      @BindView(R.id.content)
-      lateinit var content: TextView
-
-      init {
-        ButterKnife.bind(this, itemView)
-      }
-
+      private val binding: WidgetHeaderBinding
+    ) : ArchiveViewHolder(binding.root) {
       fun bind(item: ArchiveListItem.Header) {
-        title.text = item.title
-        content.text = item.content
+        binding.title.text = item.title
+        binding.content.text = item.content
       }
     }
 
     class PlaceholderViewHolder(
-      itemView: View
-    ) : ArchiveViewHolder(itemView) {
-      @BindView(R.id.content)
-      lateinit var content: TextView
-
-      init {
-        ButterKnife.bind(this, itemView)
-      }
-
+      private val binding: WidgetArchivePlaceholderBinding
+    ) : ArchiveViewHolder(binding.root) {
       fun bind(item: ArchiveListItem.Placeholder) {
-        content.text = item.content
+        binding.content.text = item.content
       }
     }
 
@@ -241,17 +211,11 @@ class ArchiveListAdapter(
       abstract fun bind(item: BufferListItem, messageSettings: MessageSettings)
 
       class StatusBuffer(
-        itemView: View,
+        private val binding: WidgetNetworkBinding,
         private val clickListener: ((BufferId) -> Unit)? = null,
         private val longClickListener: ((BufferId) -> Unit)? = null,
         private val expansionListener: ((NetworkId, Boolean) -> Unit)? = null
-      ) : BufferViewHolder(itemView) {
-        @BindView(R.id.status)
-        lateinit var status: ImageView
-
-        @BindView(R.id.name)
-        lateinit var name: TextView
-
+      ) : BufferViewHolder(binding.root) {
         var bufferId: BufferId? = null
         var networkId: NetworkId? = null
 
@@ -263,7 +227,6 @@ class ArchiveListAdapter(
         private var expanded: Boolean = false
 
         init {
-          ButterKnife.bind(this, itemView)
           itemView.setOnClickListener {
             val buffer = bufferId
             if (buffer != null)
@@ -280,7 +243,7 @@ class ArchiveListAdapter(
             }
           }
 
-          status.setOnClickListener {
+          binding.status.setOnClickListener {
             val network = networkId
             if (network != null)
               expansionListener?.invoke(network, !expanded)
@@ -298,11 +261,11 @@ class ArchiveListAdapter(
         }
 
         override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
-          name.text = item.props.name
+          binding.name.text = item.props.name
           bufferId = item.props.info.bufferId
           networkId = item.props.info.networkId
 
-          name.setTextColor(
+          binding.name.setTextColor(
             when {
               item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
               item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -316,31 +279,19 @@ class ArchiveListAdapter(
           itemView.isSelected = item.state.selected
 
           if (item.state.networkExpanded) {
-            status.setImageResource(R.drawable.ic_chevron_up)
+            binding.status.setImageResource(R.drawable.ic_chevron_up)
           } else {
-            status.setImageResource(R.drawable.ic_chevron_down)
+            binding.status.setImageResource(R.drawable.ic_chevron_down)
           }
         }
       }
 
       class GroupBuffer(
-        itemView: View,
+        private val binding: WidgetBufferBinding,
         private val clickListener: ((BufferId) -> Unit)? = null,
         private val longClickListener: ((BufferId) -> Unit)? = null,
         private val dragListener: ((BufferViewHolder) -> Unit)? = null
-      ) : BufferViewHolder(itemView) {
-        @BindView(R.id.status)
-        lateinit var status: ImageView
-
-        @BindView(R.id.name)
-        lateinit var name: TextView
-
-        @BindView(R.id.description)
-        lateinit var description: TextView
-
-        @BindView(R.id.handle)
-        lateinit var handle: View
-
+      ) : BufferViewHolder(binding.root) {
         var bufferId: BufferId? = null
 
         private val online: Drawable?
@@ -352,7 +303,6 @@ class ArchiveListAdapter(
         private var highlight: Int = 0
 
         init {
-          ButterKnife.bind(this, itemView)
           itemView.setOnClickListener {
             val buffer = bufferId
             if (buffer != null)
@@ -369,7 +319,7 @@ class ArchiveListAdapter(
             }
           }
 
-          handle.setOnTouchListener { _, event ->
+          binding.handle.setOnTouchListener { _, event ->
             if (event.action == MotionEvent.ACTION_DOWN) {
               dragListener?.invoke(this)
             }
@@ -397,10 +347,10 @@ class ArchiveListAdapter(
         override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
           bufferId = item.props.info.bufferId
 
-          name.text = item.props.name
-          description.text = item.props.description
+          binding.name.text = item.props.name
+          binding.description.text = item.props.description
 
-          name.setTextColor(
+          binding.name.setTextColor(
             when {
               item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
               item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -411,11 +361,11 @@ class ArchiveListAdapter(
 
           itemView.isSelected = item.state.selected
 
-          handle.visibleIf(item.state.showHandle)
+          binding.handle.visibleIf(item.state.showHandle)
 
-          description.visibleIf(item.props.description.isNotBlank())
+          binding.description.visibleIf(item.props.description.isNotBlank())
 
-          status.setImageDrawable(
+          binding.status.setImageDrawable(
             when (item.props.bufferStatus) {
               BufferStatus.ONLINE -> online
               else                -> offline
@@ -425,23 +375,11 @@ class ArchiveListAdapter(
       }
 
       class ChannelBuffer(
-        itemView: View,
+        private val binding: WidgetBufferBinding,
         private val clickListener: ((BufferId) -> Unit)? = null,
         private val longClickListener: ((BufferId) -> Unit)? = null,
         private val dragListener: ((BufferViewHolder) -> Unit)? = null
-      ) : BufferViewHolder(itemView) {
-        @BindView(R.id.status)
-        lateinit var status: ImageView
-
-        @BindView(R.id.name)
-        lateinit var name: TextView
-
-        @BindView(R.id.description)
-        lateinit var description: TextView
-
-        @BindView(R.id.handle)
-        lateinit var handle: View
-
+      ) : BufferViewHolder(binding.root) {
         var bufferId: BufferId? = null
 
         private var none: Int = 0
@@ -450,7 +388,6 @@ class ArchiveListAdapter(
         private var highlight: Int = 0
 
         init {
-          ButterKnife.bind(this, itemView)
           itemView.setOnClickListener {
             val buffer = bufferId
             if (buffer != null)
@@ -467,7 +404,7 @@ class ArchiveListAdapter(
             }
           }
 
-          handle.setOnTouchListener { _, event ->
+          binding.handle.setOnTouchListener { _, event ->
             if (event.action == MotionEvent.ACTION_DOWN) {
               dragListener?.invoke(this)
             }
@@ -488,10 +425,10 @@ class ArchiveListAdapter(
         override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
           bufferId = item.props.info.bufferId
 
-          name.text = item.props.name
-          description.text = item.props.description
+          binding.name.text = item.props.name
+          binding.description.text = item.props.description
 
-          name.setTextColor(
+          binding.name.setTextColor(
             when {
               item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
               item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -502,32 +439,20 @@ class ArchiveListAdapter(
 
           itemView.isSelected = item.state.selected
 
-          handle.visibleIf(item.state.showHandle)
+          binding.handle.visibleIf(item.state.showHandle)
 
-          description.visibleIf(item.props.description.isNotBlank())
+          binding.description.visibleIf(item.props.description.isNotBlank())
 
-          status.setImageDrawable(item.props.fallbackDrawable)
+          binding.status.setImageDrawable(item.props.fallbackDrawable)
         }
       }
 
       class QueryBuffer(
-        itemView: View,
+        private val binding: WidgetBufferBinding,
         private val clickListener: ((BufferId) -> Unit)? = null,
         private val longClickListener: ((BufferId) -> Unit)? = null,
         private val dragListener: ((BufferViewHolder) -> Unit)? = null
-      ) : BufferViewHolder(itemView) {
-        @BindView(R.id.status)
-        lateinit var status: ImageView
-
-        @BindView(R.id.name)
-        lateinit var name: TextView
-
-        @BindView(R.id.description)
-        lateinit var description: TextView
-
-        @BindView(R.id.handle)
-        lateinit var handle: View
-
+      ) : BufferViewHolder(binding.root) {
         var bufferId: BufferId? = null
 
         private var none: Int = 0
@@ -536,7 +461,6 @@ class ArchiveListAdapter(
         private var highlight: Int = 0
 
         init {
-          ButterKnife.bind(this, itemView)
           itemView.setOnClickListener {
             val buffer = bufferId
             if (buffer != null)
@@ -553,7 +477,7 @@ class ArchiveListAdapter(
             }
           }
 
-          handle.setOnTouchListener { _, event ->
+          binding.handle.setOnTouchListener { _, event ->
             if (event.action == MotionEvent.ACTION_DOWN) {
               dragListener?.invoke(this)
             }
@@ -574,10 +498,10 @@ class ArchiveListAdapter(
         override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
           bufferId = item.props.info.bufferId
 
-          name.text = item.props.name
-          description.text = item.props.description
+          binding.name.text = item.props.name
+          binding.description.text = item.props.description
 
-          name.setTextColor(
+          binding.name.setTextColor(
             when {
               item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
               item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -588,11 +512,11 @@ class ArchiveListAdapter(
 
           itemView.isSelected = item.state.selected
 
-          handle.visibleIf(item.state.showHandle)
+          binding.handle.visibleIf(item.state.showHandle)
 
-          description.visibleIf(item.props.description.isNotBlank())
+          binding.description.visibleIf(item.props.description.isNotBlank())
 
-          status.loadAvatars(item.props.avatarUrls,
+          binding.status.loadAvatars(item.props.avatarUrls,
                              item.props.fallbackDrawable,
                              crop = !messageSettings.squareAvatars)
         }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt
index d11f847579be380cad0113910a62a09d7ab0b631..f799c2342258a2617d6a1c47e6c471f2e9dc88e8 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -24,17 +24,16 @@ import android.view.LayoutInflater
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.helper.safeValue
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetBufferAwayBinding
+import de.kuschku.quasseldroid.databinding.WidgetBufferBinding
+import de.kuschku.quasseldroid.databinding.WidgetNetworkBinding
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.helper.*
 import de.kuschku.quasseldroid.util.lists.ListAdapter
@@ -94,34 +93,38 @@ class BufferListAdapter(
     val viewType = ViewType(viewType.toUInt())
     return when (viewType.bufferType?.enabledValues()?.firstOrNull()) {
       BufferInfo.Type.ChannelBuffer -> BufferViewHolder.ChannelBuffer(
-        LayoutInflater.from(parent.context).inflate(
-          R.layout.widget_buffer, parent, false
-        ),
-        clickListener = clickListener,
-        longClickListener = longClickListener,
-        dragListener = dragListener
-      )
-      BufferInfo.Type.QueryBuffer   -> BufferViewHolder.QueryBuffer(
-        LayoutInflater.from(parent.context).inflate(
-          if (viewType.bufferStatus == BufferStatus.AWAY) R.layout.widget_buffer_away
-          else R.layout.widget_buffer, parent, false
-        ),
+        WidgetBufferBinding.inflate(LayoutInflater.from(parent.context), parent, false),
         clickListener = clickListener,
         longClickListener = longClickListener,
         dragListener = dragListener
       )
+      BufferInfo.Type.QueryBuffer   -> if (viewType.bufferStatus == BufferStatus.AWAY) {
+        BufferViewHolder.QueryAwayBuffer(
+          WidgetBufferAwayBinding.inflate(
+            LayoutInflater.from(parent.context), parent, false
+          ),
+          clickListener = clickListener,
+          longClickListener = longClickListener,
+          dragListener = dragListener
+        )
+      } else {
+        BufferViewHolder.QueryBuffer(
+          WidgetBufferBinding.inflate(
+            LayoutInflater.from(parent.context), parent, false
+          ),
+          clickListener = clickListener,
+          longClickListener = longClickListener,
+          dragListener = dragListener
+        )
+      }
       BufferInfo.Type.GroupBuffer   -> BufferViewHolder.GroupBuffer(
-        LayoutInflater.from(parent.context).inflate(
-          R.layout.widget_buffer, parent, false
-        ),
+        WidgetBufferBinding.inflate(LayoutInflater.from(parent.context), parent, false),
         clickListener = clickListener,
         longClickListener = longClickListener,
         dragListener = dragListener
       )
       BufferInfo.Type.StatusBuffer  -> BufferViewHolder.StatusBuffer(
-        LayoutInflater.from(parent.context).inflate(
-          R.layout.widget_network, parent, false
-        ),
+        WidgetNetworkBinding.inflate(LayoutInflater.from(parent.context), parent, false),
         clickListener = clickListener,
         longClickListener = longClickListener,
         expansionListener = ::expandListener
@@ -162,17 +165,11 @@ class BufferListAdapter(
     abstract fun bind(item: BufferListItem, messageSettings: MessageSettings)
 
     class StatusBuffer(
-      itemView: View,
+      private val binding: WidgetNetworkBinding,
       private val clickListener: ((BufferId) -> Unit)? = null,
       private val longClickListener: ((BufferId) -> Unit)? = null,
       private val expansionListener: ((NetworkId, Boolean) -> Unit)? = null
-    ) : BufferViewHolder(itemView) {
-      @BindView(R.id.status)
-      lateinit var status: ImageView
-
-      @BindView(R.id.name)
-      lateinit var name: TextView
-
+    ) : BufferViewHolder(binding.root) {
       var bufferId: BufferId? = null
       var networkId: NetworkId? = null
 
@@ -184,7 +181,6 @@ class BufferListAdapter(
       private var expanded: Boolean = false
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val buffer = bufferId
           if (buffer != null)
@@ -201,7 +197,7 @@ class BufferListAdapter(
           }
         }
 
-        status.setOnClickListener {
+        binding.status.setOnClickListener {
           val network = networkId
           if (network != null)
             expansionListener?.invoke(network, !expanded)
@@ -219,11 +215,11 @@ class BufferListAdapter(
       }
 
       override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
-        name.text = item.props.name
+        binding.name.text = item.props.name
         bufferId = item.props.info.bufferId
         networkId = item.props.info.networkId
 
-        name.setTextColor(
+        binding.name.setTextColor(
           when {
             item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
             item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -237,31 +233,19 @@ class BufferListAdapter(
         itemView.isSelected = item.state.selected
 
         if (item.state.networkExpanded) {
-          status.setImageResource(R.drawable.ic_chevron_up)
+          binding.status.setImageResource(R.drawable.ic_chevron_up)
         } else {
-          status.setImageResource(R.drawable.ic_chevron_down)
+          binding.status.setImageResource(R.drawable.ic_chevron_down)
         }
       }
     }
 
     class GroupBuffer(
-      itemView: View,
+      private val binding: WidgetBufferBinding,
       private val clickListener: ((BufferId) -> Unit)? = null,
       private val longClickListener: ((BufferId) -> Unit)? = null,
       private val dragListener: ((BufferViewHolder) -> Unit)? = null
-    ) : BufferViewHolder(itemView) {
-      @BindView(R.id.status)
-      lateinit var status: ImageView
-
-      @BindView(R.id.name)
-      lateinit var name: TextView
-
-      @BindView(R.id.description)
-      lateinit var description: TextView
-
-      @BindView(R.id.handle)
-      lateinit var handle: View
-
+    ) : BufferViewHolder(binding.root) {
       var bufferId: BufferId? = null
 
       private val online: Drawable?
@@ -273,7 +257,6 @@ class BufferListAdapter(
       private var highlight: Int = 0
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val buffer = bufferId
           if (buffer != null)
@@ -290,7 +273,7 @@ class BufferListAdapter(
           }
         }
 
-        handle.setOnTouchListener { _, event ->
+        binding.handle.setOnTouchListener { _, event ->
           if (event.action == MotionEvent.ACTION_DOWN) {
             dragListener?.invoke(this)
           }
@@ -318,10 +301,10 @@ class BufferListAdapter(
       override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
         bufferId = item.props.info.bufferId
 
-        name.text = item.props.name
-        description.text = item.props.description
+        binding.name.text = item.props.name
+        binding.description.text = item.props.description
 
-        name.setTextColor(
+        binding.name.setTextColor(
           when {
             item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
             item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -332,11 +315,11 @@ class BufferListAdapter(
 
         itemView.isSelected = item.state.selected
 
-        handle.visibleIf(item.state.showHandle)
+        binding.handle.visibleIf(item.state.showHandle)
 
-        description.visibleIf(item.props.description.isNotBlank())
+        binding.description.visibleIf(item.props.description.isNotBlank())
 
-        status.setImageDrawable(
+        binding.status.setImageDrawable(
           when (item.props.bufferStatus) {
             BufferStatus.ONLINE -> online
             else                -> offline
@@ -346,23 +329,11 @@ class BufferListAdapter(
     }
 
     class ChannelBuffer(
-      itemView: View,
+      private val binding: WidgetBufferBinding,
       private val clickListener: ((BufferId) -> Unit)? = null,
       private val longClickListener: ((BufferId) -> Unit)? = null,
       private val dragListener: ((BufferViewHolder) -> Unit)? = null
-    ) : BufferViewHolder(itemView) {
-      @BindView(R.id.status)
-      lateinit var status: ImageView
-
-      @BindView(R.id.name)
-      lateinit var name: TextView
-
-      @BindView(R.id.description)
-      lateinit var description: TextView
-
-      @BindView(R.id.handle)
-      lateinit var handle: View
-
+    ) : BufferViewHolder(binding.root) {
       var bufferId: BufferId? = null
 
       private var none: Int = 0
@@ -371,7 +342,6 @@ class BufferListAdapter(
       private var highlight: Int = 0
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val buffer = bufferId
           if (buffer != null)
@@ -388,7 +358,7 @@ class BufferListAdapter(
           }
         }
 
-        handle.setOnTouchListener { _, event ->
+        binding.handle.setOnTouchListener { _, event ->
           if (event.action == MotionEvent.ACTION_DOWN) {
             dragListener?.invoke(this)
           }
@@ -409,10 +379,10 @@ class BufferListAdapter(
       override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
         bufferId = item.props.info.bufferId
 
-        name.text = item.props.name
-        description.text = item.props.description
+        binding.name.text = item.props.name
+        binding.description.text = item.props.description
 
-        name.setTextColor(
+        binding.name.setTextColor(
           when {
             item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
             item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -423,32 +393,95 @@ class BufferListAdapter(
 
         itemView.isSelected = item.state.selected
 
-        handle.visibleIf(item.state.showHandle)
+        binding.handle.visibleIf(item.state.showHandle)
 
-        description.visibleIf(item.props.description.isNotBlank())
+        binding.description.visibleIf(item.props.description.isNotBlank())
 
-        status.setImageDrawable(item.props.fallbackDrawable)
+        binding.status.setImageDrawable(item.props.fallbackDrawable)
       }
     }
 
     class QueryBuffer(
-      itemView: View,
+      private val binding: WidgetBufferBinding,
       private val clickListener: ((BufferId) -> Unit)? = null,
       private val longClickListener: ((BufferId) -> Unit)? = null,
       private val dragListener: ((BufferViewHolder) -> Unit)? = null
-    ) : BufferViewHolder(itemView) {
-      @BindView(R.id.status)
-      lateinit var status: ImageView
+    ) : BufferViewHolder(binding.root) {
+      var bufferId: BufferId? = null
+
+      private var none: Int = 0
+      private var activity: Int = 0
+      private var message: Int = 0
+      private var highlight: Int = 0
+
+      init {
+        itemView.setOnClickListener {
+          val buffer = bufferId
+          if (buffer != null)
+            clickListener?.invoke(buffer)
+        }
+
+        itemView.setOnLongClickListener {
+          val buffer = bufferId
+          if (buffer != null) {
+            longClickListener?.invoke(buffer)
+            true
+          } else {
+            false
+          }
+        }
+
+        binding.handle.setOnTouchListener { _, event ->
+          if (event.action == MotionEvent.ACTION_DOWN) {
+            dragListener?.invoke(this)
+          }
+          false
+        }
+
+        itemView.context.theme.styledAttributes(
+          R.attr.colorTextPrimary, R.attr.colorTintActivity, R.attr.colorTintMessage,
+          R.attr.colorTintHighlight
+        ) {
+          none = getColor(0, 0)
+          activity = getColor(1, 0)
+          message = getColor(2, 0)
+          highlight = getColor(3, 0)
+        }
+      }
 
-      @BindView(R.id.name)
-      lateinit var name: TextView
+      override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
+        bufferId = item.props.info.bufferId
 
-      @BindView(R.id.description)
-      lateinit var description: TextView
+        binding.name.text = item.props.info.bufferName
+        binding.description.text = item.props.description
 
-      @BindView(R.id.handle)
-      lateinit var handle: View
+        binding.name.setTextColor(
+          when {
+            item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
+            item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
+            item.props.bufferActivity.hasFlag(Buffer_Activity.OtherActivity) -> activity
+            else                                                             -> none
+          }
+        )
 
+        itemView.isSelected = item.state.selected
+
+        binding.handle.visibleIf(item.state.showHandle)
+
+        binding.description.visibleIf(item.props.description.isNotBlank())
+
+        binding.status.loadAvatars(item.props.avatarUrls,
+                                   item.props.fallbackDrawable,
+                                   crop = !messageSettings.squareAvatars)
+      }
+    }
+
+    class QueryAwayBuffer(
+      private val binding: WidgetBufferAwayBinding,
+      private val clickListener: ((BufferId) -> Unit)? = null,
+      private val longClickListener: ((BufferId) -> Unit)? = null,
+      private val dragListener: ((BufferViewHolder) -> Unit)? = null
+    ) : BufferViewHolder(binding.root) {
       var bufferId: BufferId? = null
 
       private var none: Int = 0
@@ -457,7 +490,6 @@ class BufferListAdapter(
       private var highlight: Int = 0
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val buffer = bufferId
           if (buffer != null)
@@ -474,7 +506,7 @@ class BufferListAdapter(
           }
         }
 
-        handle.setOnTouchListener { _, event ->
+        binding.handle.setOnTouchListener { _, event ->
           if (event.action == MotionEvent.ACTION_DOWN) {
             dragListener?.invoke(this)
           }
@@ -495,10 +527,10 @@ class BufferListAdapter(
       override fun bind(item: BufferListItem, messageSettings: MessageSettings) {
         bufferId = item.props.info.bufferId
 
-        name.text = item.props.info.bufferName
-        description.text = item.props.description
+        binding.name.text = item.props.info.bufferName
+        binding.description.text = item.props.description
 
-        name.setTextColor(
+        binding.name.setTextColor(
           when {
             item.props.bufferActivity.hasFlag(Buffer_Activity.Highlight)     -> highlight
             item.props.bufferActivity.hasFlag(Buffer_Activity.NewMessage)    -> message
@@ -509,11 +541,11 @@ class BufferListAdapter(
 
         itemView.isSelected = item.state.selected
 
-        handle.visibleIf(item.state.showHandle)
+        binding.handle.visibleIf(item.state.showHandle)
 
-        description.visibleIf(item.props.description.isNotBlank())
+        binding.description.visibleIf(item.props.description.isNotBlank())
 
-        status.loadAvatars(item.props.avatarUrls,
+        binding.status.loadAvatars(item.props.avatarUrls,
                            item.props.fallbackDrawable,
                            crop = !messageSettings.squareAvatars)
       }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigAdapter.kt
index 9388b791d5c94048b01fb87d540eb2d7ac745b97..f42664d5e4458ad53e4cbbd72014f491f1ba3d3a 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,16 +20,12 @@
 package de.kuschku.quasseldroid.ui.chat.buffers
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.view.ContextThemeWrapper
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemToolbarBinding
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
 class BufferViewConfigAdapter :
@@ -63,9 +59,8 @@ class BufferViewConfigAdapter :
       if (dropDown) ContextThemeWrapper(parent.context, dropDownViewTheme)
       else parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_toolbar, parent, false)
     return BufferViewConfigViewHolder(
-      view
+      WidgetSpinnerItemToolbarBinding.inflate(inflater, parent, false)
     )
   }
 
@@ -80,16 +75,11 @@ class BufferViewConfigAdapter :
 
   override fun getCount() = data.size
 
-  class BufferViewConfigViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class BufferViewConfigViewHolder(
+    private val binding: WidgetSpinnerItemToolbarBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(bufferViewConfig: BufferViewConfig?) {
-      text.text = bufferViewConfig?.bufferViewName() ?: ""
+      binding.text1.text = bufferViewConfig?.bufferViewName() ?: ""
     }
   }
 }
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 8b9b1b01d10dd54238a9bb219a6f015d1c1ebb16..cb9b27d4a16e2a758adaf5fdc9f8c5d0755a1da1 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -45,6 +45,8 @@ import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
 import de.kuschku.libquassel.util.helper.*
 import de.kuschku.quasseldroid.BuildConfig
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.persistence.dao.listenDefaultFiltered
+import de.kuschku.quasseldroid.persistence.dao.listenRx
 import de.kuschku.quasseldroid.persistence.db.AccountDatabase
 import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
 import de.kuschku.quasseldroid.persistence.models.Filtered
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt
index 6c88633fd5dea9c67adcc41adfc6dbee10b760f0..2cd66d65d01426d0f24f7f63f9cfb5e7adde54ab 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -22,16 +22,11 @@ package de.kuschku.quasseldroid.ui.chat.input
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.*
 import de.kuschku.quasseldroid.settings.MessageSettings
-import de.kuschku.quasseldroid.ui.chat.nicks.NickListAdapter.Companion.VIEWTYPE_AWAY
 import de.kuschku.quasseldroid.util.helper.loadAvatars
 import de.kuschku.quasseldroid.util.helper.visibleIf
 import de.kuschku.quasseldroid.util.ui.SpanFormatter
@@ -56,33 +51,23 @@ class AutoCompleteAdapter @Inject constructor(
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
     VIEWTYPE_CHANNEL                         -> AutoCompleteViewHolder.ChannelViewHolder(
-      LayoutInflater.from(parent.context)
-        .inflate(R.layout.widget_buffer, parent, false),
+      WidgetBufferBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+      clickListener = clickListener
+    )
+    VIEWTYPE_NICK_ACTIVE, VIEWTYPE_NICK_AWAY -> AutoCompleteViewHolder.NickViewHolder(
+      WidgetNickBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+      clickListener = clickListener
+    )
+    VIEWTYPE_NICK_AWAY                       -> AutoCompleteViewHolder.NickAwayViewHolder(
+      WidgetNickAwayBinding.inflate(LayoutInflater.from(parent.context), parent, false),
       clickListener = clickListener
     )
-    VIEWTYPE_NICK_ACTIVE, VIEWTYPE_NICK_AWAY -> {
-      val holder = AutoCompleteViewHolder.NickViewHolder(
-        LayoutInflater.from(parent.context).inflate(
-          when (viewType) {
-            VIEWTYPE_AWAY -> R.layout.widget_nick_away
-            else          -> R.layout.widget_nick
-          }, parent, false
-        ),
-        clickListener = clickListener
-      )
-
-      holder.avatar.visibleIf(messageSettings.showAvatars)
-
-      holder
-    }
     VIEWTYPE_ALIAS                           -> AutoCompleteViewHolder.AliasViewHolder(
-      LayoutInflater.from(parent.context)
-        .inflate(R.layout.widget_alias, parent, false),
+      WidgetAliasBinding.inflate(LayoutInflater.from(parent.context), parent, false),
       clickListener = clickListener
     )
     VIEWTYPE_EMOJI                           -> AutoCompleteViewHolder.EmojiViewHolder(
-      LayoutInflater.from(parent.context)
-        .inflate(R.layout.widget_emoji, parent, false),
+      WidgetEmojiBinding.inflate(LayoutInflater.from(parent.context), parent, false),
       clickListener = clickListener
     )
     else                                     -> throw IllegalArgumentException(
@@ -118,22 +103,39 @@ class AutoCompleteAdapter @Inject constructor(
     }
 
     class NickViewHolder(
-      itemView: View,
+      private val binding: WidgetNickBinding,
       private val clickListener: ((String, String) -> Unit)? = null
-    ) : AutoCompleteViewHolder(itemView) {
-      @BindView(R.id.avatar)
-      lateinit var avatar: ImageView
+    ) : AutoCompleteViewHolder(binding.root) {
+      var value: AutoCompleteItem? = null
 
-      @BindView(R.id.nick)
-      lateinit var nick: TextView
+      init {
+        itemView.setOnClickListener {
+          val value = value
+          if (value != null)
+            clickListener?.invoke(value.name, value.suffix)
+        }
+      }
 
-      @BindView(R.id.realname)
-      lateinit var realname: TextView
+      fun bindImpl(data: AutoCompleteItem.UserItem, messageSettings: MessageSettings) {
+        value = data
+
+        binding.nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
+        binding.realname.text = data.realname
 
+        binding.avatar.visibleIf(messageSettings.showAvatars)
+        binding.avatar.loadAvatars(data.avatarUrls,
+                                   data.fallbackDrawable,
+                                   crop = !messageSettings.squareAvatars)
+      }
+    }
+
+    class NickAwayViewHolder(
+      private val binding: WidgetNickAwayBinding,
+      private val clickListener: ((String, String) -> Unit)? = null
+    ) : AutoCompleteViewHolder(binding.root) {
       var value: AutoCompleteItem? = null
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val value = value
           if (value != null)
@@ -144,32 +146,23 @@ class AutoCompleteAdapter @Inject constructor(
       fun bindImpl(data: AutoCompleteItem.UserItem, messageSettings: MessageSettings) {
         value = data
 
-        nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
-        realname.text = data.realname
+        binding.nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
+        binding.realname.text = data.realname
 
-        avatar.loadAvatars(data.avatarUrls,
+        binding.avatar.visibleIf(messageSettings.showAvatars)
+        binding.avatar.loadAvatars(data.avatarUrls,
                            data.fallbackDrawable,
                            crop = !messageSettings.squareAvatars)
       }
     }
 
     class ChannelViewHolder(
-      itemView: View,
+      private val binding: WidgetBufferBinding,
       private val clickListener: ((String, String) -> Unit)? = null
-    ) : AutoCompleteViewHolder(itemView) {
-      @BindView(R.id.status)
-      lateinit var status: ImageView
-
-      @BindView(R.id.name)
-      lateinit var name: TextView
-
-      @BindView(R.id.description)
-      lateinit var description: TextView
-
+    ) : AutoCompleteViewHolder(binding.root) {
       var value: AutoCompleteItem? = null
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val value = value
           if (value != null)
@@ -180,29 +173,22 @@ class AutoCompleteAdapter @Inject constructor(
       fun bindImpl(data: AutoCompleteItem.ChannelItem, messageSettings: MessageSettings) {
         value = data
 
-        name.text = data.info.bufferName
-        description.text = data.description
+        binding.name.text = data.info.bufferName
+        binding.description.text = data.description
 
-        description.visibleIf(data.description.isNotBlank())
+        binding.description.visibleIf(data.description.isNotBlank())
 
-        status.setImageDrawable(data.icon)
+        binding.status.setImageDrawable(data.icon)
       }
     }
 
     class AliasViewHolder(
-      itemView: View,
+      private val binding: WidgetAliasBinding,
       private val clickListener: ((String, String) -> Unit)? = null
-    ) : AutoCompleteViewHolder(itemView) {
-      @BindView(R.id.alias)
-      lateinit var alias: TextView
-
-      @BindView(R.id.expansion)
-      lateinit var expansion: TextView
-
+    ) : AutoCompleteViewHolder(binding.root) {
       var value: AutoCompleteItem? = null
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val value = value
           if (value != null)
@@ -213,25 +199,18 @@ class AutoCompleteAdapter @Inject constructor(
       fun bindImpl(data: AutoCompleteItem.AliasItem, messageSettings: MessageSettings) {
         value = data
 
-        alias.text = data.alias
-        expansion.text = data.expansion
+        binding.alias.text = data.alias
+        binding.expansion.text = data.expansion
       }
     }
 
     class EmojiViewHolder(
-      itemView: View,
+      private val binding: WidgetEmojiBinding,
       private val clickListener: ((String, String) -> Unit)? = null
-    ) : AutoCompleteViewHolder(itemView) {
-      @BindView(R.id.emoji)
-      lateinit var emoji: TextView
-
-      @BindView(R.id.shortCode)
-      lateinit var shortCode: TextView
-
+    ) : AutoCompleteViewHolder(binding.root) {
       var value: AutoCompleteItem? = null
 
       init {
-        ButterKnife.bind(this, itemView)
         itemView.setOnClickListener {
           val value = value
           if (value != null)
@@ -242,8 +221,8 @@ class AutoCompleteAdapter @Inject constructor(
       fun bindImpl(data: AutoCompleteItem.EmojiItem, messageSettings: MessageSettings) {
         value = data
 
-        emoji.text = data.replacement
-        shortCode.text = data.shortCodes.joinToString(", ")
+        binding.emoji.text = data.replacement
+        binding.shortCode.text = data.shortCodes.joinToString(", ")
       }
     }
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/MessageHistoryAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/MessageHistoryAdapter.kt
index 43e5354fca6fb54c8d974106436c3573bca631a1..1a5e35449993c638020c6a556aab1fd13cd38ef3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/MessageHistoryAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/MessageHistoryAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -21,14 +21,10 @@ package de.kuschku.quasseldroid.ui.chat.input
 
 import android.text.TextUtils
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetHistoryMessageBinding
 import de.kuschku.quasseldroid.util.lists.ListAdapter
 
 class MessageHistoryAdapter : ListAdapter<CharSequence, MessageHistoryAdapter.MessageViewHolder>(
@@ -52,7 +48,7 @@ class MessageHistoryAdapter : ListAdapter<CharSequence, MessageHistoryAdapter.Me
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
     MessageViewHolder(
-      LayoutInflater.from(parent.context).inflate(R.layout.widget_history_message, parent, false),
+      WidgetHistoryMessageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
       clickListener = clickListener
     )
 
@@ -64,16 +60,12 @@ class MessageHistoryAdapter : ListAdapter<CharSequence, MessageHistoryAdapter.Me
     holder.bind(getItem(position))
 
   class MessageViewHolder(
-    itemView: View,
+    private val binding: WidgetHistoryMessageBinding,
     private val clickListener: ((CharSequence) -> Unit)? = null
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.content)
-    lateinit var content: TextView
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     var value: CharSequence? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         val value = value
         if (value != null)
@@ -83,7 +75,7 @@ class MessageHistoryAdapter : ListAdapter<CharSequence, MessageHistoryAdapter.Me
 
     fun bind(data: CharSequence) {
       value = data
-      content.text = data
+      binding.content.text = data
     }
   }
 }
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 2d2e3fc2404a8f988b758d1cc2b4ffe33f9e72ae..6c682499f840547233b7b57e27c5a9a188706e5b 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -29,8 +29,6 @@ import android.widget.TextView
 import androidx.paging.PagedListAdapter
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.util.flag.hasFlag
@@ -46,7 +44,7 @@ import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage
 import javax.inject.Inject
 
 class MessageAdapter @Inject constructor(
-  private val messageRenderer: MessageRenderer
+  private val messageRenderer: QuasselMessageRenderer
 ) : PagedListAdapter<DisplayMessage, MessageAdapter.QuasselMessageViewHolder>(
   object : DiffUtil.ItemCallback<DisplayMessage>() {
     override fun areItemsTheSame(oldItem: DisplayMessage, newItem: DisplayMessage) =
@@ -185,45 +183,16 @@ class MessageAdapter @Inject constructor(
     expansionListener: ((MessageData) -> Unit)? = null,
     movementMethod: BetterLinkMovementMethod
   ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.daychange_container)
-    @JvmField
-    var daychangeContainer: View? = null
-
-    @BindView(R.id.daychange)
-    @JvmField
-    var daychange: TextView? = null
-
-    @BindView(R.id.message_container)
-    @JvmField
-    var messageContainer: View? = null
-
-    @BindView(R.id.time_left)
-    @JvmField
-    var timeLeft: TextView? = null
-
-    @BindView(R.id.time_right)
-    @JvmField
-    var timeRight: TextView? = null
-
-    @BindView(R.id.avatar)
-    @JvmField
-    var avatar: ImageView? = null
-
-    @BindView(R.id.name)
-    @JvmField
-    var name: TextView? = null
-
-    @BindView(R.id.realname)
-    @JvmField
-    var realname: TextView? = null
-
-    @BindView(R.id.content)
-    @JvmField
-    var content: TextView? = null
-
-    @BindView(R.id.combined)
-    @JvmField
-    var combined: TextView? = null
+    val daychangeContainer: View? = itemView.findViewById(R.id.daychange_container)
+    val daychange: TextView? = itemView.findViewById(R.id.daychange)
+    val messageContainer: View? = itemView.findViewById(R.id.message_container)
+    val timeLeft: TextView? = itemView.findViewById(R.id.time_left)
+    val timeRight: TextView? = itemView.findViewById(R.id.time_right)
+    val avatar: ImageView? = itemView.findViewById(R.id.avatar)
+    val name: TextView? = itemView.findViewById(R.id.name)
+    val realname: TextView? = itemView.findViewById(R.id.realname)
+    val content: TextView? = itemView.findViewById(R.id.content)
+    val combined: TextView? = itemView.findViewById(R.id.combined)
 
     private var message: FormattedMessage? = null
     private var original: MessageData? = null
@@ -254,7 +223,6 @@ class MessageAdapter @Inject constructor(
     }
 
     init {
-      ButterKnife.bind(this, itemView)
       content?.movementMethod = movementMethod
       combined?.movementMethod = movementMethod
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt
index ca9421adab0b0172aa8dbdd2679b9754fa313292..199a10486e6cb8465d1480aea013b411f384f63b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -22,16 +22,13 @@ package de.kuschku.quasseldroid.ui.chat.nicks
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.util.helper.nullIf
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetNickAwayBinding
+import de.kuschku.quasseldroid.databinding.WidgetNickBinding
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.helper.letIf
 import de.kuschku.quasseldroid.util.helper.loadAvatars
@@ -56,20 +53,15 @@ class NickListAdapter(
     (it.initial.nullIf(String?::isNullOrBlank) ?: "123")
   }
 
-  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NickViewHolder {
-    val holder = NickViewHolder(
-      LayoutInflater.from(parent.context).inflate(
-        when (viewType) {
-          VIEWTYPE_AWAY -> R.layout.widget_nick_away
-          else          -> R.layout.widget_nick
-        }, parent, false
-      ),
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
+    VIEWTYPE_AWAY -> NickViewHolder.Away(
+      WidgetNickAwayBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+      clickListener = clickListener
+    )
+    else          -> NickViewHolder.Active(
+      WidgetNickBinding.inflate(LayoutInflater.from(parent.context), parent, false),
       clickListener = clickListener
     )
-
-    holder.avatar.visibleIf(messageSettings.showAvatars)
-
-    return holder
   }
 
   operator fun get(position: Int): IrcUserItem? = super.getItem(position)
@@ -83,39 +75,61 @@ class NickListAdapter(
     VIEWTYPE_ACTIVE
   }
 
-  class NickViewHolder(
-    itemView: View,
-    private val clickListener: ((NetworkId, String) -> Unit)? = null
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.avatar)
-    lateinit var avatar: ImageView
-
-    @BindView(R.id.nick)
-    lateinit var nick: TextView
+  sealed class NickViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+    abstract fun bind(data: IrcUserItem, messageSettings: MessageSettings)
+
+    class Active(
+      private val binding: WidgetNickBinding,
+      private val clickListener: ((NetworkId, String) -> Unit)? = null
+    ) : NickViewHolder(binding.root) {
+      var user: IrcUserItem? = null
+
+      init {
+        itemView.setOnClickListener {
+          val nick = user
+          if (nick != null)
+            clickListener?.invoke(nick.networkId, nick.nick)
+        }
+      }
 
-    @BindView(R.id.realname)
-    lateinit var realname: TextView
+      override fun bind(data: IrcUserItem, messageSettings: MessageSettings) {
+        user = data
 
-    var user: IrcUserItem? = null
+        binding.nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
+        binding.realname.text = data.realname
 
-    init {
-      ButterKnife.bind(this, itemView)
-      itemView.setOnClickListener {
-        val nick = user
-        if (nick != null)
-          clickListener?.invoke(nick.networkId, nick.nick)
+        binding.avatar.visibleIf(messageSettings.showAvatars)
+        binding.avatar.loadAvatars(data.avatarUrls,
+                                   data.fallbackDrawable,
+                                   crop = !messageSettings.squareAvatars)
       }
     }
 
-    fun bind(data: IrcUserItem, messageSettings: MessageSettings) {
-      user = data
+    class Away(
+      private val binding: WidgetNickAwayBinding,
+      private val clickListener: ((NetworkId, String) -> Unit)? = null
+    ) : NickViewHolder(binding.root) {
+      var user: IrcUserItem? = null
+
+      init {
+        itemView.setOnClickListener {
+          val nick = user
+          if (nick != null)
+            clickListener?.invoke(nick.networkId, nick.nick)
+        }
+      }
+
+      override fun bind(data: IrcUserItem, messageSettings: MessageSettings) {
+        user = data
 
-      nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
-      realname.text = data.realname
+        binding.nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
+        binding.realname.text = data.realname
 
-      avatar.loadAvatars(data.avatarUrls,
-                         data.fallbackDrawable,
-                         crop = !messageSettings.squareAvatars)
+        binding.avatar.visibleIf(messageSettings.showAvatars)
+        binding.avatar.loadAvatars(data.avatarUrls,
+                                   data.fallbackDrawable,
+                                   crop = !messageSettings.squareAvatars)
+      }
     }
   }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt
index b95fde5ea811a3c5c96b933441536be8cee019dd..239348782174f4cefdba5b798e2000413aa2273e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -210,7 +210,7 @@ class AboutFragment : DaggerFragment() {
       ),
       Library(
         name = "Kotlin Standard Library",
-        version = "1.3.50",
+        version = "1.3.61",
         license = apache2,
         url = "https://kotlinlang.org/"
       ),
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/ContributorAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/ContributorAdapter.kt
index 0d653187426a0d8e9bbd68e4f0151c0803b376b3..18a2a987a90c5a74aec4ec4b0e068830e5108600 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/ContributorAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/ContributorAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,18 +20,14 @@
 package de.kuschku.quasseldroid.ui.clientsettings.about
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetContributorBinding
 
 class ContributorAdapter(private val contributors: List<Contributor>) :
   RecyclerView.Adapter<ContributorAdapter.ContributorViewHolder>() {
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ContributorViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.widget_contributor, parent, false)
+    WidgetContributorBinding.inflate(LayoutInflater.from(parent.context), parent, false)
   )
 
   override fun getItemCount() = contributors.size
@@ -40,24 +36,13 @@ class ContributorAdapter(private val contributors: List<Contributor>) :
     holder.bind(contributors[position])
   }
 
-  class ContributorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.nickname)
-    lateinit var nickName: TextView
-
-    @BindView(R.id.description)
-    lateinit var description: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class ContributorViewHolder(
+    private val binding: WidgetContributorBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(item: Contributor) {
-      this.name.text = item.name
-      this.nickName.text = item.nickName
-      this.description.text = item.description
+      binding.name.text = item.name
+      binding.nickname.text = item.nickName
+      binding.description.text = item.description
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt
index 6aa04b99b6c3292bfb852e7fa0ecbc04aabaf304..580a3346092216c3a0abb4735a74b2388ded48ab 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,20 +20,16 @@
 package de.kuschku.quasseldroid.ui.clientsettings.about
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetLibraryBinding
 import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseActivity
 import de.kuschku.quasseldroid.util.helper.visibleIf
 
 class LibraryAdapter(private val libraries: List<Library>) :
   RecyclerView.Adapter<LibraryAdapter.LibraryViewHolder>() {
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = LibraryViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.widget_library, parent, false)
+    WidgetLibraryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
   )
 
   override fun getItemCount() = libraries.size
@@ -42,20 +38,12 @@ class LibraryAdapter(private val libraries: List<Library>) :
     holder.bind(libraries[position])
   }
 
-  class LibraryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.version)
-    lateinit var version: TextView
-
-    @BindView(R.id.license)
-    lateinit var license: TextView
-
+  class LibraryViewHolder(
+    private val binding: WidgetLibraryBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: Library? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         this.item?.run {
           LicenseActivity.launch(itemView.context,
@@ -67,10 +55,10 @@ class LibraryAdapter(private val libraries: List<Library>) :
 
     fun bind(item: Library) {
       this.item = item
-      this.name.text = item.name
-      this.version.text = item.version
-      this.version.visibleIf(!item.version.isNullOrBlank())
-      this.license.text = item.license.shortName
+      binding.name.text = item.name
+      binding.version.text = item.version
+      binding.version.visibleIf(!item.version.isNullOrBlank())
+      binding.license.text = item.license.shortName
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/TranslatorAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/TranslatorAdapter.kt
index 551caf0f5b5791968c79175325071db810545f53..eed99ce24ff7aab979063bf71b4b3bde39be1955 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/TranslatorAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/TranslatorAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,18 +20,16 @@
 package de.kuschku.quasseldroid.ui.clientsettings.about
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetTranslatorBinding
 
 class TranslatorAdapter(private val translators: List<Translator>) :
   RecyclerView.Adapter<TranslatorAdapter.TranslatorViewHolder>() {
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = TranslatorViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.widget_translator, parent, false)
+    WidgetTranslatorBinding.inflate(
+      LayoutInflater.from(parent.context), parent, false
+    )
   )
 
   override fun getItemCount() = translators.size
@@ -40,20 +38,12 @@ class TranslatorAdapter(private val translators: List<Translator>) :
     holder.bind(translators[position])
   }
 
-  class TranslatorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.language)
-    lateinit var language: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class TranslatorViewHolder(
+    private val binding: WidgetTranslatorBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(item: Translator) {
-      this.name.text = item.name
-      this.language.text = itemView.resources.getString(item.language)
+      binding.name.text = item.name
+      binding.language.text = itemView.resources.getString(item.language)
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt
index afda307d98997674386b90167f9e54ca2d3dd500..6e575a30c512bdb3b45fb714dd9f503f5825c5ae 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -66,13 +66,13 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
   override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
     setPreferencesFromResource(R.xml.preferences, rootKey)
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-      findPreference(getString(R.string.preference_notification_sound_key)).isVisible = false
-      findPreference(getString(R.string.preference_notification_vibration_key)).isVisible = false
-      findPreference(getString(R.string.preference_notification_light_key)).isVisible = false
+      findPreference<Preference>(getString(R.string.preference_notification_sound_key))?.isVisible = false
+      findPreference<Preference>(getString(R.string.preference_notification_vibration_key))?.isVisible = false
+      findPreference<Preference>(getString(R.string.preference_notification_light_key))?.isVisible = false
     } else {
-      findPreference(getString(R.string.preference_notification_configure_key)).isVisible = false
+      findPreference<Preference>(getString(R.string.preference_notification_configure_key))?.isVisible = false
     }
-    findPreference(getString(R.string.preference_clear_cache_key)).setOnPreferenceClickListener {
+    findPreference<Preference>(getString(R.string.preference_clear_cache_key))?.setOnPreferenceClickListener {
       activity?.let {
         handler.post {
           QuasselDatabase.Creator.init(it).message().clearMessages()
@@ -93,8 +93,8 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
     super.onStop()
   }
 
-  override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
-    updateSummary(findPreference(key))
+  override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String) {
+    updateSummary(findPreference<ListPreference>(key))
     val appearanceSettings = Settings.appearance(context!!)
     if (this.appearanceSettings.theme != appearanceSettings.theme ||
         this.appearanceSettings.language != appearanceSettings.language) {
@@ -102,8 +102,8 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
     }
   }
 
-  private fun updateSummary(preference: Preference) {
-    if (preference is ListPreference) {
+  private fun updateSummary(preference: ListPreference?) {
+    if (preference != null) {
       preference.summary = preference.entry
     }
   }
@@ -111,7 +111,7 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
   private fun initSummary(preference: Preference) {
     if (preference is PreferenceGroup) {
       (0 until preference.preferenceCount).asSequence().map(preference::getPreference).forEach(::initSummary)
-    } else {
+    } else if (preference is ListPreference) {
       updateSummary(preference)
     }
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashAdapter.kt
index 70337ec0e25eef821936458542c709ca6f8b8cc0..f53335c5ac4fedde064ce77831bae2bed08d95d3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -22,40 +22,37 @@ package de.kuschku.quasseldroid.ui.clientsettings.crash
 import android.content.Intent
 import android.net.Uri
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.malheur.data.Report
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetCrashBinding
 import de.kuschku.quasseldroid.util.lists.ListAdapter
 import org.threeten.bp.Instant
 import org.threeten.bp.ZoneId
 import org.threeten.bp.format.DateTimeFormatter
 
-class CrashAdapter : ListAdapter<Pair<Report, Uri>, CrashAdapter.CrashViewHolder>(
-  object : DiffUtil.ItemCallback<Pair<Report, Uri>>() {
-    override fun areItemsTheSame(oldItem: Pair<Report, Uri>, newItem: Pair<Report, Uri>) =
+class CrashAdapter : ListAdapter<Pair<Report?, Uri>, CrashAdapter.CrashViewHolder>(
+  object : DiffUtil.ItemCallback<Pair<Report?, Uri>>() {
+    override fun areItemsTheSame(oldItem: Pair<Report?, Uri>, newItem: Pair<Report?, Uri>) =
       oldItem.second == newItem.second
 
-    override fun areContentsTheSame(oldItem: Pair<Report, Uri>, newItem: Pair<Report, Uri>) =
+    override fun areContentsTheSame(oldItem: Pair<Report?, Uri>, newItem: Pair<Report?, Uri>) =
       oldItem == newItem
   }
 ) {
-  private var onUpdateListener: ((List<Pair<Report, Uri>>) -> Unit)? = null
-  fun setOnUpdateListener(listener: ((List<Pair<Report, Uri>>) -> Unit)?) {
+  private var onUpdateListener: ((List<Pair<Report?, Uri>>) -> Unit)? = null
+  fun setOnUpdateListener(listener: ((List<Pair<Report?, Uri>>) -> Unit)?) {
     onUpdateListener = listener
   }
 
-  override fun onUpdateFinished(list: List<Pair<Report, Uri>>) {
+  override fun onUpdateFinished(list: List<Pair<Report?, Uri>>) {
     onUpdateListener?.invoke(list)
   }
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = CrashViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.widget_crash, parent, false)
+    WidgetCrashBinding.inflate(LayoutInflater.from(parent.context), parent, false)
   )
 
   override fun onBindViewHolder(holder: CrashViewHolder, position: Int) {
@@ -63,23 +60,16 @@ class CrashAdapter : ListAdapter<Pair<Report, Uri>, CrashAdapter.CrashViewHolder
     holder.bind(report, uri)
   }
 
-  class CrashViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.crash_time)
-    lateinit var crashTime: TextView
+  class CrashViewHolder(
+    private val binding: WidgetCrashBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
 
-    @BindView(R.id.version_name)
-    lateinit var versionName: TextView
-
-    @BindView(R.id.error)
-    lateinit var error: TextView
-
-    var item: Report? = null
-    var uri: Uri? = null
+    private var item: Report? = null
+    private var uri: Uri? = null
 
     private val dateTimeFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss")
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         uri?.let {
           itemView.context.startActivity(
@@ -96,15 +86,15 @@ class CrashAdapter : ListAdapter<Pair<Report, Uri>, CrashAdapter.CrashViewHolder
       }
     }
 
-    fun bind(item: Report, uri: Uri) {
+    fun bind(item: Report?, uri: Uri) {
       this.item = item
       this.uri = uri
 
-      this.crashTime.text = item.environment?.crashTime?.let {
+      binding.crashTime.text = item?.environment?.crashTime?.let {
         dateTimeFormatter.format(Instant.ofEpochMilli(it).atZone(ZoneId.systemDefault()))
-      }
-      this.versionName.text = "${item.application?.versionName}"
-      this.error.text = "${item.crash?.exception?.lines()?.firstOrNull()}"
+      } ?: "null"
+      binding.versionName.text = item?.application?.versionName ?: "null"
+      binding.error.text = item?.crash?.exception?.lines()?.firstOrNull() ?: "null"
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt
index f7f29a269e47d1d6ccc4e5834206848af8322a7e..2e3f47d5e340ba5e40896404aa6a8a22d3484443 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -33,6 +33,7 @@ import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
 import com.google.gson.Gson
+import com.google.gson.JsonSyntaxException
 import dagger.android.support.DaggerFragment
 import de.kuschku.malheur.CrashHandler
 import de.kuschku.malheur.data.Report
@@ -78,15 +79,19 @@ class CrashFragment : DaggerFragment() {
 
     if (crashDir != null && context != null) {
       crashDir.mkdirs()
-      val list: List<Pair<Report, Uri>> = crashDir.listFiles()
+      val list: List<Pair<Report?, Uri>> = crashDir.listFiles()
         .orEmpty()
         .map {
-          Pair<Report, Uri>(
-            gson.fromJson(it.readText()),
+          Pair<Report?, Uri>(
+            try {
+              gson.fromJson<Report>(it.readText())
+            } catch (e: JsonSyntaxException) {
+              null
+            },
             FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.fileprovider", it)
           )
         }
-        .sortedByDescending { it.first.environment?.crashTime }
+        .sortedByDescending { it.first?.environment?.crashTime }
 
       activity?.runOnUiThread {
         this.adapter?.submitList(list)
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt
index 397e67314b8a2ec5c28a61e71ac88e936b4c857d..4e25c57d65e0c3041eaf14c4bbefa0d5a7c23a66 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.clientsettings.license
 
 import android.content.Context
 import android.content.Intent
-import androidx.annotation.StringRes
+import androidx.annotation.RawRes
 import de.kuschku.quasseldroid.util.ui.settings.SettingsActivity
 
 class LicenseActivity : SettingsActivity(LicenseFragment()) {
@@ -29,13 +29,13 @@ class LicenseActivity : SettingsActivity(LicenseFragment()) {
     fun launch(
       context: Context,
       license_name: String,
-      @StringRes license_text: Int
+      @RawRes license_text: Int
     ) = context.startActivity(intent(context, license_name, license_text))
 
     fun intent(
       context: Context,
       license_name: String,
-      @StringRes license_text: Int
+      @RawRes license_text: Int
     ) = Intent(context, LicenseActivity::class.java).apply {
       putExtra("license_name", license_name)
       putExtra("license_text", license_text)
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 56d8049458317527b938d4baf97ac89dae2ebe35..b9c33fc215d7e40a21dbff7adea9054693abda9f 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,14 +20,9 @@
 package de.kuschku.quasseldroid.ui.clientsettings.whitelist
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
-import androidx.appcompat.widget.AppCompatImageButton
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.PreferencesWhitelistCertificateItemBinding
 import de.kuschku.quasseldroid.persistence.models.SslValidityWhitelistEntry
 import de.kuschku.quasseldroid.util.helper.setTooltip
 import de.kuschku.quasseldroid.util.helper.visibleIf
@@ -83,9 +78,9 @@ class WhitelistCertificateAdapter :
   override fun getItemCount() = data.size
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = WhitelistItemViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.preferences_whitelist_certificate_item,
-                                                parent,
-                                                false),
+    PreferencesWhitelistCertificateItemBinding.inflate(
+      LayoutInflater.from(parent.context), parent, false
+    ),
     ::remove
   )
 
@@ -94,34 +89,24 @@ class WhitelistCertificateAdapter :
   }
 
   class WhitelistItemViewHolder(
-    itemView: View,
+    private val binding: PreferencesWhitelistCertificateItemBinding,
     clickListener: ((SslValidityWhitelistEntry) -> Unit)?
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.fingerprint)
-    lateinit var fingerprint: TextView
-
-    @BindView(R.id.ignore_date)
-    lateinit var ignoreDate: View
-
-    @BindView(R.id.action_delete)
-    lateinit var delete: AppCompatImageButton
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: SslValidityWhitelistEntry? = null
 
     init {
-      ButterKnife.bind(this, itemView)
-      delete.setOnClickListener {
+      binding.actionDelete.setOnClickListener {
         item?.let {
           clickListener?.invoke(it)
         }
       }
-      delete.setTooltip()
+      binding.actionDelete.setTooltip()
     }
 
     fun bind(item: SslValidityWhitelistEntry) {
       this.item = item
-      fingerprint.text = item.fingerprint
-      ignoreDate.visibleIf(item.ignoreDate)
+      binding.fingerprint.text = item.fingerprint
+      binding.ignoreDate.visibleIf(item.ignoreDate)
     }
   }
 }
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 fe3d5e1c87d0ffd96300b24403e2a1ad02711a31..c257748ecb336f0b7b468e371e25c2aec1019f49 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,14 +20,9 @@
 package de.kuschku.quasseldroid.ui.clientsettings.whitelist
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
-import androidx.appcompat.widget.AppCompatImageButton
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.PreferencesWhitelistHostnameItemBinding
 import de.kuschku.quasseldroid.persistence.models.SslHostnameWhitelistEntry
 import de.kuschku.quasseldroid.util.helper.setTooltip
 
@@ -77,9 +72,9 @@ class WhitelistHostnameAdapter :
   override fun getItemCount() = data.size
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = WhitelistItemViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.preferences_whitelist_hostname_item,
-                                                parent,
-                                                false),
+    PreferencesWhitelistHostnameItemBinding.inflate(
+      LayoutInflater.from(parent.context), parent, false
+    ),
     ::remove
   )
 
@@ -88,34 +83,24 @@ class WhitelistHostnameAdapter :
   }
 
   class WhitelistItemViewHolder(
-    itemView: View,
+    private val binding: PreferencesWhitelistHostnameItemBinding,
     clickListener: ((SslHostnameWhitelistEntry) -> Unit)?
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.hostname)
-    lateinit var hostname: TextView
-
-    @BindView(R.id.fingerprint)
-    lateinit var fingerprint: TextView
-
-    @BindView(R.id.action_delete)
-    lateinit var delete: AppCompatImageButton
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: SslHostnameWhitelistEntry? = null
 
     init {
-      ButterKnife.bind(this, itemView)
-      delete.setOnClickListener {
+      binding.actionDelete.setOnClickListener {
         item?.let {
           clickListener?.invoke(it)
         }
       }
-      delete.setTooltip()
+      binding.actionDelete.setTooltip()
     }
 
     fun bind(item: SslHostnameWhitelistEntry) {
       this.item = item
-      hostname.text = item.hostname
-      fingerprint.text = item.fingerprint
+      binding.hostname.text = item.hostname
+      binding.fingerprint.text = item.fingerprint
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/SettingsItemAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/SettingsItemAdapter.kt
index be6bed9606022d5e2e3f27be01400571636ac711..c23439f3e5a8ba1b3f31980689317cbf7d96baf3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/SettingsItemAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/SettingsItemAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.ui.coresettings
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.SettingsItemBinding
 
 class SettingsItemAdapter<T>(private val clickListener: (T) -> Unit) :
   ListAdapter<SettingsItem<T>, SettingsItemAdapter.SettingsItemViewHolder<T>>(
@@ -41,7 +37,7 @@ class SettingsItemAdapter<T>(private val clickListener: (T) -> Unit) :
     }
   ) {
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = SettingsItemViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.settings_item, parent, false),
+    SettingsItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     clickListener
   )
 
@@ -49,15 +45,13 @@ class SettingsItemAdapter<T>(private val clickListener: (T) -> Unit) :
     holder.bind(getItem(position))
   }
 
-  class SettingsItemViewHolder<T>(itemView: View, clickListener: (T) -> Unit) :
-    RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.title)
-    lateinit var title: TextView
-
+  class SettingsItemViewHolder<T>(
+    private val binding: SettingsItemBinding,
+    clickListener: (T) -> Unit
+  ) : RecyclerView.ViewHolder(binding.root) {
     var id: T? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         id?.let(clickListener::invoke)
       }
@@ -65,7 +59,7 @@ class SettingsItemAdapter<T>(private val clickListener: (T) -> Unit) :
 
     fun bind(item: SettingsItem<T>) {
       this.id = item.id
-      this.title.text = item.name
+      binding.title.text = item.name
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListAdapter.kt
index e9e4d5535d907d9bb5f4bc3bf8d59f47c1e997c4..0421df00601d852688ffd11518a51f3371985a92 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -21,14 +21,10 @@ package de.kuschku.quasseldroid.ui.coresettings.aliaslist
 
 import android.view.LayoutInflater
 import android.view.MotionEvent
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.SettingsAliaslistItemBinding
 import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
 import java.util.*
 import javax.inject.Inject
@@ -84,7 +80,7 @@ class AliasListAdapter @Inject constructor(
   override fun getItemCount() = data.size
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = AliasItemViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.settings_aliaslist_item, parent, false),
+    SettingsAliaslistItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     formatDeserializer,
     clickListener,
     dragListener
@@ -95,30 +91,20 @@ class AliasListAdapter @Inject constructor(
   }
 
   class AliasItemViewHolder(
-    itemView: View,
+    private val binding: SettingsAliaslistItemBinding,
     private val formatDeserializer: IrcFormatDeserializer,
     clickListener: ((IAliasManager.Alias) -> Unit)?,
     dragListener: ((AliasItemViewHolder) -> Unit)?
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.expansion)
-    lateinit var expansion: TextView
-
-    @BindView(R.id.handle)
-    lateinit var handle: View
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: IAliasManager.Alias? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         item?.let {
           clickListener?.invoke(it)
         }
       }
-      handle.setOnTouchListener { _, event ->
+      binding.handle.setOnTouchListener { _, event ->
         if (event.action == MotionEvent.ACTION_DOWN) {
           dragListener?.invoke(this)
         }
@@ -128,8 +114,8 @@ class AliasListAdapter @Inject constructor(
 
     fun bind(item: IAliasManager.Alias) {
       this.item = item
-      name.text = item.name
-      expansion.text = formatDeserializer.formatString(item.expansion, true)
+      binding.name.text = item.name
+      binding.expansion.text = formatDeserializer.formatString(item.expansion, true)
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt
index 1e1c1b3344b87f9b9a0d36653f1b85b5bb4b58a1..5d3c46ea7bc2609a614358f55964a7fdc3160085 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatListBaseFragment.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -126,7 +126,7 @@ abstract class ChatListBaseFragment(private val initDefault: Boolean) :
       combineLatest(it.values.map(Network::liveNetworkInfo)).map {
         it.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, INetwork.NetworkInfo::networkName))
       }
-    }.toLiveData().observe(this, Observer {
+    }.toLiveData().observe(viewLifecycleOwner, Observer {
       if (it != null) {
         val selectOriginal = networkId.selectedItemId == Spinner.INVALID_ROW_ID
         networkAdapter.submitList(listOf(null) + it)
@@ -143,7 +143,7 @@ abstract class ChatListBaseFragment(private val initDefault: Boolean) :
         .filter(Optional<ISession>::isPresent)
         .map(Optional<ISession>::get)
         .firstElement()
-        .toLiveData().observe(this, Observer {
+        .toLiveData().observe(viewLifecycleOwner, Observer {
           it?.let {
             update(Defaults.bufferViewConfig(requireContext(), it.proxy),
                    minimumActivityAdapter,
@@ -155,7 +155,7 @@ abstract class ChatListBaseFragment(private val initDefault: Boolean) :
         .filter(Optional<BufferViewConfig>::isPresent)
         .map(Optional<BufferViewConfig>::get)
         .firstElement()
-        .toLiveData().observe(this, Observer {
+        .toLiveData().observe(viewLifecycleOwner, Observer {
           it?.let {
             update(it, minimumActivityAdapter, networkAdapter)
           }
@@ -169,11 +169,11 @@ abstract class ChatListBaseFragment(private val initDefault: Boolean) :
       }
 
       override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
-        if (id == -1L) {
+        if (NetworkId(id.toInt()).isValidId()) {
+          showStatusBuffer.isEnabled = true
+        } else {
           showStatusBuffer.isChecked = true
           showStatusBuffer.isEnabled = false
-        } else {
-          showStatusBuffer.isEnabled = true
         }
       }
     }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/MinimumActivityAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/MinimumActivityAdapter.kt
index 0d74323e8f42bff223b0c7bdc1fe98fe095f668e..303f053e520c4d2bdbfbef0551014414cf766a1b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/MinimumActivityAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/MinimumActivityAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.ui.coresettings.chatlist
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.Buffer_Activities
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -49,9 +45,8 @@ class MinimumActivityAdapter(val data: List<MinimumActivityItem>) :
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
     return MinimumActivityViewHolder(
-      view
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
     )
   }
 
@@ -72,17 +67,12 @@ class MinimumActivityAdapter(val data: List<MinimumActivityItem>) :
     return null
   }
 
-  class MinimumActivityViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class MinimumActivityViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(activity: MinimumActivityItem?) {
       activity?.let {
-        text.setText(it.name)
+        binding.text1.setText(it.name)
       }
     }
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/NetworkAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/NetworkAdapter.kt
index 0bd71bc604d3cf647cc148b34f77508a4c62006c..c937b7b8ab64e69d096a1ee82bfefee4e926279d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/NetworkAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/NetworkAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,17 +20,13 @@
 package de.kuschku.quasseldroid.ui.coresettings.chatlist
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.annotation.StringRes
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -57,13 +53,13 @@ class NetworkAdapter(@StringRes private val fallbackName: Int) :
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
-    return NetworkViewHolder(fallbackName, view)
+    return NetworkViewHolder(fallbackName,
+                             WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false))
   }
 
   fun indexOf(id: NetworkId): Int? {
     for ((key, item) in data.withIndex()) {
-      if (item?.networkId ?: -1 == id) {
+      if (item?.networkId ?: 0 == id) {
         return key
       }
     }
@@ -71,20 +67,15 @@ class NetworkAdapter(@StringRes private val fallbackName: Int) :
   }
 
   override fun getItem(position: Int): INetwork.NetworkInfo? = data[position]
-  override fun getItemId(position: Int) = getItem(position)?.networkId?.id?.toLong() ?: -1
+  override fun getItemId(position: Int) = getItem(position)?.networkId?.id?.toLong() ?: 0
   override fun hasStableIds() = true
   override fun getCount() = data.size
-  class NetworkViewHolder(@StringRes private val fallbackName: Int, itemView: View) :
-    RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class NetworkViewHolder(
+    @StringRes private val fallbackName: Int,
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(network: INetwork.NetworkInfo?) {
-      text.text = network?.networkName ?: itemView.context.getString(fallbackName)
+      binding.text1.text = network?.networkName ?: itemView.context.getString(fallbackName)
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightNickTypeAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightNickTypeAdapter.kt
index cee4362f78e493e2dd5f9e85af6a89745a261ddc..6fcba82d71ad181b84c865125064f372fddf0d5b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightNickTypeAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightNickTypeAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.ui.coresettings.highlightlist
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.interfaces.IHighlightRuleManager
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -49,9 +45,8 @@ class HighlightNickTypeAdapter(val data: List<HighlightNickTypeItem>) :
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
     return HighlightNickTypeViewHolder(
-      view
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
     )
   }
 
@@ -72,17 +67,12 @@ class HighlightNickTypeAdapter(val data: List<HighlightNickTypeItem>) :
     return null
   }
 
-  class HighlightNickTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class HighlightNickTypeViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(activity: HighlightNickTypeItem?) {
       activity?.let {
-        text.setText(it.name)
+        binding.text1.setText(it.name)
       }
     }
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightRuleAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightRuleAdapter.kt
index 27ab704d3270a1cb0691a472e141900c366d0cf2..6617cd3480e2b92486a7f1b9f4e37104f5e49973 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightRuleAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightRuleAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -21,15 +21,10 @@ package de.kuschku.quasseldroid.ui.coresettings.highlightlist
 
 import android.view.LayoutInflater
 import android.view.MotionEvent
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
-import androidx.appcompat.widget.SwitchCompat
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.HighlightRuleManager
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.SettingsHighlightlistRuleBinding
 import de.kuschku.quasseldroid.util.helper.visibleIf
 import java.util.*
 
@@ -79,8 +74,7 @@ class HighlightRuleAdapter(
   override fun getItemCount() = data.size
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = HighlightRuleViewHolder(
-    LayoutInflater.from(parent.context)
-      .inflate(R.layout.settings_highlightlist_rule, parent, false),
+    SettingsHighlightlistRuleBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     clickListener,
     ::toggle,
     dragListener
@@ -91,53 +85,25 @@ class HighlightRuleAdapter(
   }
 
   class HighlightRuleViewHolder(
-    itemView: View,
+    private val binding: SettingsHighlightlistRuleBinding,
     clickListener: (HighlightRuleManager.HighlightRule) -> Unit,
     toggleListener: (HighlightRuleManager.HighlightRule, Boolean) -> Unit,
     dragListener: (HighlightRuleViewHolder) -> Unit
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.name_row)
-    lateinit var nameRow: View
-
-    @BindView(R.id.sender)
-    lateinit var sender: TextView
-
-    @BindView(R.id.sender_row)
-    lateinit var senderRow: View
-
-    @BindView(R.id.channel)
-    lateinit var channel: TextView
-
-    @BindView(R.id.channel_row)
-    lateinit var channelRow: View
-
-    @BindView(R.id.match_all)
-    lateinit var matchAll: View
-
-    @BindView(R.id.toggle)
-    lateinit var toggle: SwitchCompat
-
-    @BindView(R.id.handle)
-    lateinit var handle: View
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: HighlightRuleManager.HighlightRule? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         item?.let {
           clickListener(it)
         }
       }
-      toggle.setOnCheckedChangeListener { _, isChecked ->
+      binding.toggle.setOnCheckedChangeListener { _, isChecked ->
         item?.let {
           toggleListener.invoke(it, isChecked)
         }
       }
-      handle.setOnTouchListener { _, event ->
+      binding.handle.setOnTouchListener { _, event ->
         if (event.action == MotionEvent.ACTION_DOWN) {
           dragListener.invoke(this)
         }
@@ -147,15 +113,15 @@ class HighlightRuleAdapter(
 
     fun bind(item: HighlightRuleManager.HighlightRule) {
       this.item = item
-      name.text = item.name
-      nameRow.visibleIf(item.name.isNotBlank())
-      sender.text = item.sender
-      senderRow.visibleIf(item.sender.isNotBlank())
-      channel.text = item.channel
-      channelRow.visibleIf(item.channel.isNotBlank())
-      matchAll.visibleIf(item.name.isBlank() && item.sender.isBlank() && item.channel.isBlank())
-
-      toggle.isChecked = item.isEnabled
+      binding.name.text = item.name
+      binding.nameRow.visibleIf(item.name.isNotBlank())
+      binding.sender.text = item.sender
+      binding.senderRow.visibleIf(item.sender.isNotBlank())
+      binding.channel.text = item.channel
+      binding.channelRow.visibleIf(item.channel.isNotBlank())
+      binding.matchAll.visibleIf(item.name.isBlank() && item.sender.isBlank() && item.channel.isBlank())
+
+      binding.toggle.isChecked = item.isEnabled
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityNicksAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityNicksAdapter.kt
index a88eca11133f26e9efb165fe1881b02fce7a3d99..9c93b6ed6454d7e08d8b6620afc4b21c49b45c66 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityNicksAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityNicksAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -21,13 +21,9 @@ package de.kuschku.quasseldroid.ui.coresettings.identity
 
 import android.view.LayoutInflater
 import android.view.MotionEvent
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.SettingsIdentityNickBinding
 import java.util.*
 
 class IdentityNicksAdapter(
@@ -70,8 +66,7 @@ class IdentityNicksAdapter(
   override fun getItemCount() = data.size
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = IdentityNickViewHolder(
-    LayoutInflater.from(parent.context)
-      .inflate(R.layout.settings_identity_nick, parent, false),
+    SettingsIdentityNickBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     clickListener,
     dragListener
   )
@@ -81,27 +76,19 @@ class IdentityNicksAdapter(
   }
 
   class IdentityNickViewHolder(
-    itemView: View,
+    private val binding: SettingsIdentityNickBinding,
     private val clickListener: (Int, String) -> Unit,
     dragListener: (IdentityNickViewHolder) -> Unit
-  ) :
-    RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.nick)
-    lateinit var nick: TextView
-
-    @BindView(R.id.handle)
-    lateinit var handle: View
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: String? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         item?.let {
           clickListener(adapterPosition, it)
         }
       }
-      handle.setOnTouchListener { _, event ->
+      binding.handle.setOnTouchListener { _, event ->
         if (event.action == MotionEvent.ACTION_DOWN) {
           dragListener.invoke(this)
         }
@@ -111,7 +98,7 @@ class IdentityNicksAdapter(
 
     fun bind(item: String) {
       this.item = item
-      nick.text = item
+      binding.nick.text = item
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreTypeAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreTypeAdapter.kt
index d1b9008ed6c50ab4075a87f8fdceca07545fab90..2edb86a3a48611be0275db652c0f7b1a29d8f0d4 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreTypeAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreTypeAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.ui.coresettings.ignoreitem
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.IgnoreListManager
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -49,9 +45,8 @@ class IgnoreTypeAdapter(val data: List<IgnoreTypeItem>) :
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
     return IgnoreTypeViewHolder(
-      view
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
     )
   }
 
@@ -72,17 +67,12 @@ class IgnoreTypeAdapter(val data: List<IgnoreTypeItem>) :
     return null
   }
 
-  class IgnoreTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class IgnoreTypeViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(activity: IgnoreTypeItem?) {
       activity?.let {
-        text.setText(it.name)
+        binding.text1.setText(it.name)
       }
     }
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/ScopeTypeAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/ScopeTypeAdapter.kt
index f039fe15c9e53a8b01f4b35ca0fe4a6f05288030..1d0f4a1b8e7facfe94dfa113529ad41febf24613 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/ScopeTypeAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/ScopeTypeAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.ui.coresettings.ignoreitem
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.IgnoreListManager
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -49,9 +45,8 @@ class ScopeTypeAdapter(val data: List<ScopeTypeItem>) :
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
     return ScopeTypeViewHolder(
-      view
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
     )
   }
 
@@ -72,17 +67,12 @@ class ScopeTypeAdapter(val data: List<ScopeTypeItem>) :
     return null
   }
 
-  class ScopeTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class ScopeTypeViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(activity: ScopeTypeItem?) {
       activity?.let {
-        text.setText(it.name)
+        binding.text1.setText(it.name)
       }
     }
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/StrictnessTypeAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/StrictnessTypeAdapter.kt
index a9f1dcbc4a02c8edd5342c5548eabfe1bd70560b..4963c098e408abd55d8569457d407d769de4a56f 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/StrictnessTypeAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/StrictnessTypeAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.ui.coresettings.ignoreitem
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.IgnoreListManager
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -49,9 +45,8 @@ class StrictnessTypeAdapter(val data: List<StrictnessTypeItem>) :
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
     return StrictnessTypeViewHolder(
-      view
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
     )
   }
 
@@ -72,17 +67,12 @@ class StrictnessTypeAdapter(val data: List<StrictnessTypeItem>) :
     return null
   }
 
-  class StrictnessTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class StrictnessTypeViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(activity: StrictnessTypeItem?) {
       activity?.let {
-        text.setText(it.name)
+        binding.text1.setText(it.name)
       }
     }
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListAdapter.kt
index cd8b17d2a77597f8b90d2ab2e747c0cfe145f24b..962ffd1bd71d4e3ef8db436e7cb1465101396474 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -21,15 +21,10 @@ package de.kuschku.quasseldroid.ui.coresettings.ignorelist
 
 import android.view.LayoutInflater
 import android.view.MotionEvent
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
-import androidx.appcompat.widget.SwitchCompat
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.IgnoreListManager
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.SettingsIgnorelistItemBinding
 import de.kuschku.quasseldroid.util.helper.visibleIf
 import java.util.*
 
@@ -79,7 +74,7 @@ class IgnoreListAdapter(
   override fun getItemCount() = data.size
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = IgnoreItemViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.settings_ignorelist_item, parent, false),
+    SettingsIgnorelistItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     clickListener,
     ::toggle,
     dragListener
@@ -90,38 +85,25 @@ class IgnoreListAdapter(
   }
 
   class IgnoreItemViewHolder(
-    itemView: View,
+    private val binding: SettingsIgnorelistItemBinding,
     clickListener: (IgnoreListManager.IgnoreListItem) -> Unit,
     toggleListener: (IgnoreListManager.IgnoreListItem, Boolean) -> Unit,
     dragListener: (IgnoreItemViewHolder) -> Unit
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.ignore_rule)
-    lateinit var ignoreRule: TextView
-
-    @BindView(R.id.scope_rule)
-    lateinit var scopeRule: TextView
-
-    @BindView(R.id.toggle)
-    lateinit var toggle: SwitchCompat
-
-    @BindView(R.id.handle)
-    lateinit var handle: View
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: IgnoreListManager.IgnoreListItem? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         item?.let {
           clickListener(it)
         }
       }
-      toggle.setOnCheckedChangeListener { _, isChecked ->
+      binding.toggle.setOnCheckedChangeListener { _, isChecked ->
         item?.let {
           toggleListener.invoke(it, isChecked)
         }
       }
-      handle.setOnTouchListener { _, event ->
+      binding.handle.setOnTouchListener { _, event ->
         if (event.action == MotionEvent.ACTION_DOWN) {
           dragListener.invoke(this)
         }
@@ -131,10 +113,10 @@ class IgnoreListAdapter(
 
     fun bind(item: IgnoreListManager.IgnoreListItem) {
       this.item = item
-      ignoreRule.text = item.ignoreRule
-      scopeRule.text = item.scopeRule
-      scopeRule.visibleIf(item.scopeRule.isNotBlank() && item.scope != IgnoreListManager.ScopeType.GlobalScope)
-      toggle.isChecked = item.isActive
+      binding.ignoreRule.text = item.ignoreRule
+      binding.scopeRule.text = item.scopeRule
+      binding.scopeRule.visibleIf(item.scopeRule.isNotBlank() && item.scope != IgnoreListManager.ScopeType.GlobalScope)
+      binding.toggle.isChecked = item.isActive
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/IdentityAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/IdentityAdapter.kt
index 4c9692791c068959a3f132919f3166b0d11a6238..4624ecadcde9c4cf997259c1ab19f6edb3a891c6 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/IdentityAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/IdentityAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,16 +20,12 @@
 package de.kuschku.quasseldroid.ui.coresettings.network
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.IdentityId
 import de.kuschku.libquassel.quassel.syncables.Identity
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -47,12 +43,13 @@ class IdentityAdapter : RecyclerSpinnerAdapter<IdentityAdapter.NetworkViewHolder
   override fun onBindViewHolder(holder: NetworkViewHolder, position: Int) =
     holder.bind(getItem(position))
 
-  override fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean)
-    : NetworkViewHolder {
+  override fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean): NetworkViewHolder {
     val inflater = LayoutInflater.from(
       if (dropDown) ContextThemeWrapper(parent.context, dropDownViewTheme) else parent.context
     )
-    return NetworkViewHolder(inflater.inflate(R.layout.widget_spinner_item_material, parent, false))
+    return NetworkViewHolder(
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
+    )
   }
 
   fun indexOf(id: IdentityId): Int? {
@@ -73,16 +70,11 @@ class IdentityAdapter : RecyclerSpinnerAdapter<IdentityAdapter.NetworkViewHolder
 
   override fun getCount() = data.size
 
-  class NetworkViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class NetworkViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(network: Identity?) {
-      text.text = network?.identityName()
+      binding.text1.text = network?.identityName()
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkServerAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkServerAdapter.kt
index 7b2832685ec60d680fda954e49b7a43da43ae1c8..30a2d4ff90ffe9959b8a45a85d1fbb1ddf5cd449 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkServerAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkServerAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -22,15 +22,11 @@ package de.kuschku.quasseldroid.ui.coresettings.network
 import android.graphics.drawable.Drawable
 import android.view.LayoutInflater
 import android.view.MotionEvent
-import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.SettingsNetworkServerBinding
 import de.kuschku.quasseldroid.util.helper.getVectorDrawableCompat
 import de.kuschku.quasseldroid.util.helper.styledAttributes
 import de.kuschku.quasseldroid.util.helper.tint
@@ -86,7 +82,7 @@ class NetworkServerAdapter(
   override fun getItemCount() = data.size
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = NetworkServerViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.settings_network_server, parent, false),
+    SettingsNetworkServerBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     clickListener,
     dragListener
   )
@@ -96,22 +92,10 @@ class NetworkServerAdapter(
   }
 
   class NetworkServerViewHolder(
-    itemView: View,
+    private val binding: SettingsNetworkServerBinding,
     clickListener: (INetwork.Server) -> Unit,
     dragListener: (NetworkServerViewHolder) -> Unit
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.host)
-    lateinit var host: TextView
-
-    @BindView(R.id.port)
-    lateinit var port: TextView
-
-    @BindView(R.id.ssl_enabled)
-    lateinit var sslEnabled: ImageView
-
-    @BindView(R.id.handle)
-    lateinit var handle: View
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var item: INetwork.Server? = null
 
     private val secure: Drawable?
@@ -119,13 +103,12 @@ class NetworkServerAdapter(
     private val insecure: Drawable?
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         item?.let {
           clickListener(it)
         }
       }
-      handle.setOnTouchListener { _, event ->
+      binding.handle.setOnTouchListener { _, event ->
         if (event.action == MotionEvent.ACTION_DOWN) {
           dragListener.invoke(this)
         }
@@ -147,9 +130,9 @@ class NetworkServerAdapter(
 
     fun bind(item: INetwork.Server) {
       this.item = item
-      host.text = item.host
-      port.text = item.port.toString()
-      sslEnabled.setImageDrawable(
+      binding.host.text = item.host
+      binding.port.text = item.port.toString()
+      binding.sslEnabled.setImageDrawable(
         when {
           item.useSsl && item.sslVerify -> secure
           item.useSsl                   -> partiallySecure
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/ProxyTypeAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/ProxyTypeAdapter.kt
index e45e17ec20e0db343a8188544906b39153bae95c..62a974ac8e6086cb0415466a86ea537498e2cfb9 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/ProxyTypeAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/ProxyTypeAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,14 +20,10 @@
 package de.kuschku.quasseldroid.ui.coresettings.networkserver
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
 import de.kuschku.quasseldroid.util.ui.RecyclerSpinnerAdapter
 
@@ -47,7 +43,7 @@ class ProxyTypeAdapter(val data: List<ProxyTypeItem>) :
       else parent.context
     )
     return ProxyTypeViewHolder(
-      inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
     )
   }
 
@@ -68,17 +64,12 @@ class ProxyTypeAdapter(val data: List<ProxyTypeItem>) :
     return null
   }
 
-  class ProxyTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class ProxyTypeViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(activity: ProxyTypeItem?) {
       activity?.let {
-        text.setText(it.name)
+        binding.text1.setText(it.name)
       }
     }
   }
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 6bb3d6fa373284afa8793ebd092431f7a33f2f9b..1f6c77c5e5e9a512bc3b50fca9ba5c5437b98492 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -38,6 +38,7 @@ import de.kuschku.libquassel.util.helper.mapMapNullable
 import de.kuschku.libquassel.util.helper.mapSwitchMap
 import de.kuschku.libquassel.util.helper.value
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.persistence.dao.findById
 import de.kuschku.quasseldroid.persistence.db.AccountDatabase
 import de.kuschku.quasseldroid.persistence.models.Account
 import de.kuschku.quasseldroid.util.TextValidator
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/channellist/ChannelListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/channellist/ChannelListAdapter.kt
index 7b2881f2a4cf2606ce1dc10b67913440a7025924..d79a732d9916d02fb05cde1ddffb88fe6348e99b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/info/channellist/ChannelListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/channellist/ChannelListAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -22,17 +22,13 @@ package de.kuschku.quasseldroid.ui.info.channellist
 import android.content.Context
 import android.graphics.drawable.Drawable
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.syncables.IrcListHelper
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetChannelSearchBinding
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
 import de.kuschku.quasseldroid.util.ColorContext
 import de.kuschku.quasseldroid.util.helper.styledAttributes
@@ -63,7 +59,7 @@ class ChannelListAdapter @Inject constructor(
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChannelViewHolder {
     return ChannelViewHolder(
-      LayoutInflater.from(parent.context).inflate(R.layout.widget_channel_search, parent, false),
+      WidgetChannelSearchBinding.inflate(LayoutInflater.from(parent.context), parent, false),
       contentFormatter,
       fallbackDrawable
     )
@@ -74,27 +70,14 @@ class ChannelListAdapter @Inject constructor(
   }
 
   class ChannelViewHolder(
-    itemView: View,
+    private val binding: WidgetChannelSearchBinding,
     private val contentFormatter: ContentFormatter,
     fallbackDrawable: Drawable
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.status)
-    lateinit var status: ImageView
-
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.users)
-    lateinit var users: TextView
-
-    @BindView(R.id.topic)
-    lateinit var topic: TextView
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     private var data: IrcListHelper.ChannelDescription? = null
 
     init {
-      ButterKnife.bind(this, itemView)
-      status.setImageDrawable(fallbackDrawable)
+      binding.status.setImageDrawable(fallbackDrawable)
       itemView.setOnClickListener {
         data?.let {
           ChatActivity.launch(
@@ -107,13 +90,13 @@ class ChannelListAdapter @Inject constructor(
     }
 
     fun bind(data: IrcListHelper.ChannelDescription) {
-      name.text = data.channelName
+      binding.name.text = data.channelName
       val (content, hasSpoilers) = contentFormatter.formatContent(
         data.topic,
         networkId = data.netId
       )
-      topic.text = content
-      users.text = itemView.context.resources.getQuantityString(R.plurals.label_user_count,
+      binding.topic.text = content
+      binding.users.text = itemView.context.resources.getQuantityString(R.plurals.label_user_count,
                                                                 data.userCount.toInt(),
                                                                 data.userCount.toInt())
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/core/ClientAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/core/ClientAdapter.kt
index 4c6c7f6da791a2ce164d3c33dd35cff1f98a373b..a504286ac928dfdd9c3c932f0ac17979933e3ef3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/info/core/ClientAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/core/ClientAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -22,19 +22,14 @@ package de.kuschku.quasseldroid.ui.info.core
 import android.graphics.drawable.Drawable
 import android.text.Html
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.Button
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.quassel.ExtendedFeature
 import de.kuschku.libquassel.quassel.syncables.CoreInfo
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetClientBinding
 import de.kuschku.quasseldroid.util.helper.getVectorDrawableCompat
 import de.kuschku.quasseldroid.util.helper.styledAttributes
 import de.kuschku.quasseldroid.util.helper.tint
@@ -71,7 +66,7 @@ class ClientAdapter : ListAdapter<CoreInfo.ConnectedClientData, ClientAdapter.Cl
   }
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ClientViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.widget_client, parent, false),
+    WidgetClientBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     dateTimeFormatter,
     dateFormatter,
     ::disconnect,
@@ -85,30 +80,12 @@ class ClientAdapter : ListAdapter<CoreInfo.ConnectedClientData, ClientAdapter.Cl
     holder.bind(getItem(position))
 
   class ClientViewHolder(
-    itemView: View,
+    private val binding: WidgetClientBinding,
     private val dateTimeFormatter: DateTimeFormatter,
     private val dateFormatter: DateTimeFormatter,
     private val disconnectListener: (Int) -> Unit,
     movementMethod: BetterLinkMovementMethod
-  ) : RecyclerView.ViewHolder(itemView) {
-
-    @BindView(R.id.ip)
-    lateinit var ip: TextView
-
-    @BindView(R.id.version)
-    lateinit var version: TextView
-
-    @BindView(R.id.uptime)
-    lateinit var uptime: TextView
-
-    @BindView(R.id.location)
-    lateinit var location: TextView
-
-    @BindView(R.id.secure_icon)
-    lateinit var secureIcon: ImageView
-
-    @BindView(R.id.disconnect)
-    lateinit var disconnect: Button
+  ) : RecyclerView.ViewHolder(binding.root) {
 
     private var id: Int? = null
 
@@ -116,9 +93,8 @@ class ClientAdapter : ListAdapter<CoreInfo.ConnectedClientData, ClientAdapter.Cl
     private val insecure: Drawable?
 
     init {
-      ButterKnife.bind(this, itemView)
-      version.movementMethod = movementMethod
-      disconnect.setOnClickListener {
+      binding.version.movementMethod = movementMethod
+      binding.disconnect.setOnClickListener {
         id?.let(disconnectListener::invoke)
       }
 
@@ -136,21 +112,21 @@ class ClientAdapter : ListAdapter<CoreInfo.ConnectedClientData, ClientAdapter.Cl
     fun bind(data: CoreInfo.ConnectedClientData) {
       id = data.id
 
-      ip.text = data.remoteAddress
+      binding.ip.text = data.remoteAddress
       val versionTime = data.clientVersionDate.toLongOrNull()
       val formattedVersionTime = if (versionTime != null)
         dateFormatter.format(Instant.ofEpochSecond(versionTime).atZone(ZoneId.systemDefault()))
       else
         data.clientVersionDate
-      version.text = Html.fromHtml(data.clientVersion + " ($formattedVersionTime)")
+      binding.version.text = Html.fromHtml(data.clientVersion + " ($formattedVersionTime)")
       val connectedSinceFormatted = dateTimeFormatter.format(data.connectedSince.atZone(ZoneId.systemDefault()))
-      uptime.text = itemView.context.getString(R.string.label_core_connected_since,
-                                               connectedSinceFormatted)
-      location.text = data.location
-      location.visibleIf(data.location.isNotBlank())
+      binding.uptime.text = itemView.context.getString(R.string.label_core_connected_since,
+                                                       connectedSinceFormatted)
+      binding.location.text = data.location
+      binding.location.visibleIf(data.location.isNotBlank())
 
-      secureIcon.setImageDrawable(if (data.secure) secure else insecure)
-      disconnect.visibleIf(data.features.hasFeature(ExtendedFeature.RemoteDisconnect))
+      binding.secureIcon.setImageDrawable(if (data.secure) secure else insecure)
+      binding.disconnect.visibleIf(data.features.hasFeature(ExtendedFeature.RemoteDisconnect))
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/ChannelAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/ChannelAdapter.kt
index d58c3b103dc538c2268699c435bf60e24804b2fc..365450c1d74bb594f3636c4d11c05b6069af46e0 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/ChannelAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/ChannelAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,17 +20,12 @@
 package de.kuschku.quasseldroid.ui.info.user
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.quassel.BufferInfo
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetBufferBinding
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
 import de.kuschku.quasseldroid.util.helper.visibleIf
 import de.kuschku.quasseldroid.util.lists.ListAdapter
@@ -51,9 +46,7 @@ class ChannelAdapter : ListAdapter<BufferProps, ChannelAdapter.ChannelViewHolder
   }
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ChannelViewHolder(
-    LayoutInflater.from(parent.context).inflate(
-      R.layout.widget_buffer, parent, false
-    ),
+    WidgetBufferBinding.inflate(LayoutInflater.from(parent.context), parent, false),
     clickListener = clickListener
   )
 
@@ -61,22 +54,12 @@ class ChannelAdapter : ListAdapter<BufferProps, ChannelAdapter.ChannelViewHolder
     holder.bind(getItem(position))
 
   class ChannelViewHolder(
-    itemView: View,
+    private val binding: WidgetBufferBinding,
     private val clickListener: ((NetworkId, String) -> Unit)? = null
-  ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.status)
-    lateinit var status: ImageView
-
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.description)
-    lateinit var description: TextView
-
+  ) : RecyclerView.ViewHolder(binding.root) {
     var info: BufferInfo? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         info?.let {
           ChatActivity.launch(
@@ -91,12 +74,12 @@ class ChannelAdapter : ListAdapter<BufferProps, ChannelAdapter.ChannelViewHolder
     fun bind(props: BufferProps) {
       info = props.info
 
-      name.text = props.info.bufferName
-      description.text = props.description
+      binding.name.text = props.info.bufferName
+      binding.description.text = props.description
 
-      description.visibleIf(props.description.isNotBlank())
+      binding.description.visibleIf(props.description.isNotBlank())
 
-      status.setImageDrawable(props.fallbackDrawable)
+      binding.status.setImageDrawable(props.fallbackDrawable)
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditActivity.kt
index 6c31f7e48a0ca5472a79c6122e7cc8cef8f8e7ba..0ef69a9d417536a31a1ba5f05c4eafe61fd25edb 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/edit/AccountEditActivity.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -21,20 +21,21 @@ package de.kuschku.quasseldroid.ui.setup.accounts.edit
 
 import android.content.Context
 import android.content.Intent
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import de.kuschku.quasseldroid.util.ui.settings.SettingsActivity
 
 class AccountEditActivity : SettingsActivity(AccountEditFragment()) {
   companion object {
     fun launch(
       context: Context,
-      account: Long
+      account: AccountId
     ) = context.startActivity(intent(context, account))
 
     fun intent(
       context: Context,
-      account: Long
+      account: AccountId
     ) = Intent(context, AccountEditActivity::class.java).apply {
-      putExtra("account", account)
+      putExtra("account", account.id)
     }
   }
 }
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 f2edca7219eb486d5aeea2e5f88cff4d81a7eb5d..1b35c06b80cc021f6ea36f20c9b12b878ec4bad3 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -35,8 +35,10 @@ 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.dao.findById
 import de.kuschku.quasseldroid.persistence.db.AccountDatabase
 import de.kuschku.quasseldroid.persistence.models.Account
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import de.kuschku.quasseldroid.util.Patterns
 import de.kuschku.quasseldroid.util.TextValidator
 import de.kuschku.quasseldroid.util.helper.editCommit
@@ -79,7 +81,7 @@ class AccountEditFragment : SettingsFragment(), Changeable, Savable, Deletable {
   lateinit var database: AccountDatabase
 
   private var account: Account? = null
-  private var accountId: Long = -1L
+  private var accountId: AccountId = AccountId(-1L)
 
   private lateinit var handlerThread: HandlerThread
   private lateinit var handler: Handler
@@ -104,8 +106,8 @@ class AccountEditFragment : SettingsFragment(), Changeable, Savable, Deletable {
     setHasOptionsMenu(true)
 
     handler.post {
-      accountId = arguments?.getLong("account", -1) ?: -1
-      if (accountId == -1L) {
+      accountId = AccountId(arguments?.getLong("account", -1L) ?: -1L)
+      if (!accountId.isValidId()) {
         activity?.setResult(Activity.RESULT_CANCELED)
         activity?.finish()
       }
@@ -187,8 +189,8 @@ class AccountEditFragment : SettingsFragment(), Changeable, Savable, Deletable {
     handler.post {
       account?.let {
         val preferences = activity?.getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
-        if (preferences?.getLong(Keys.Status.selectedAccount, -1) == it.id) {
-          preferences.editCommit {
+        if (AccountId(preferences?.getLong(Keys.Status.selectedAccount, -1) ?: -1) == it.id) {
+          preferences?.editCommit {
             remove(Keys.Status.selectedAccount)
           }
         }
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 4d35029842ecb6b5890a83367353f1a33bf0f028..381b9e592c46a739dda5ecf4991d798c19b5be5c 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -19,117 +19,58 @@
 
 package de.kuschku.quasseldroid.ui.setup.accounts.selection
 
-import android.annotation.SuppressLint
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
-import androidx.appcompat.widget.AppCompatImageButton
-import androidx.appcompat.widget.AppCompatRadioButton
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.Observer
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetCoreAccountAddBinding
+import de.kuschku.quasseldroid.databinding.WidgetCoreAccountBinding
 import de.kuschku.quasseldroid.persistence.models.Account
-import de.kuschku.quasseldroid.util.helper.zip
-
-class AccountAdapter(
-  owner: LifecycleOwner,
-  liveData: LiveData<List<Account>>,
-  private val selectedItem: MutableLiveData<Pair<Long, Long>>
-) : RecyclerView.Adapter<AccountAdapter.AccountViewHolder>() {
-  private val actionListeners = mutableSetOf<(Long) -> Unit>()
-  private val addListeners = mutableSetOf<() -> Unit>()
-  private val selectionListeners = mutableSetOf<(Long) -> Unit>()
+import de.kuschku.quasseldroid.persistence.util.AccountId
+import de.kuschku.quasseldroid.util.lists.ListAdapter
 
-  private val clickListener = object :
-    ItemListener {
-    override fun onAction(id: Long, pos: Int) {
-      selectionListener.invoke(id)
-    }
+class AccountAdapter : ListAdapter<Pair<Account?, Boolean>, AccountAdapter.AccountViewHolder>(
+  object : DiffUtil.ItemCallback<Pair<Account?, Boolean>>() {
+    override fun areItemsTheSame(oldItem: Pair<Account?, Boolean>,
+                                 newItem: Pair<Account?, Boolean>) =
+      oldItem.first?.id == newItem.first?.id
+
+    override fun areContentsTheSame(oldItem: Pair<Account?, Boolean>,
+                                    newItem: Pair<Account?, Boolean>) =
+      oldItem == newItem
   }
+) {
+  private val actionListeners = mutableSetOf<(AccountId) -> Unit>()
+  private val addListeners = mutableSetOf<() -> Unit>()
+  private val clickListeners = mutableSetOf<(AccountId) -> Unit>()
 
-  private val actionListener = object :
-    ItemListener {
-    override fun onAction(id: Long, pos: Int) {
+  private val actionListener = object : ItemListener {
+    override fun onAction(id: AccountId, pos: Int) {
       for (actionListener in actionListeners) {
         actionListener.invoke(id)
       }
     }
   }
 
-  private fun updateSelection(id: Long) {
-    selectedItem.value = Pair(selectedItem.value?.second ?: -1, id)
-  }
-
-  private val selectionListener = { id: Long ->
-    updateSelection(id)
-    for (selectionListener in selectionListeners) {
-      selectionListener.invoke(id)
+  private val addListener = object : AddListener {
+    override fun onAction() {
+      for (addListener in addListeners) {
+        addListener.invoke()
+      }
     }
   }
 
-  val selectedItemId
-    get() = selectedItem.value?.second
-
-  private var list: List<Pair<Boolean, Account>> = emptyList()
-
-  init {
-    selectedItem.value = Pair(-1, -1)
-
-    liveData.zip(selectedItem).observe(owner, Observer { it ->
-      val list = it?.first
-      val oldSelected = it?.second?.first ?: -1
-      val selected = it?.second?.second ?: -1
-
-      val oldList = this.list
-      val newList: List<Pair<Boolean, Account>> = list.orEmpty().map {
-        Pair(selected == it.id, it)
+  private val clickListener = object : ItemListener {
+    override fun onAction(id: AccountId, pos: Int) {
+      for (clickListener in clickListeners) {
+        clickListener.invoke(id)
       }
-      this.list = newList
-
-      DiffUtil.calculateDiff(object : DiffUtil.Callback() {
-        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
-          val oldItem = oldList[oldItemPosition].second
-          val newItem = newList[newItemPosition].second
-
-          return oldItem.id == newItem.id
-        }
-
-        override fun getOldListSize(): Int {
-          return oldList.size
-        }
-
-        override fun getNewListSize(): Int {
-          return newList.size
-        }
-
-        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
-          val oldItem = oldList[oldItemPosition].second
-          val newItem = newList[newItemPosition].second
-
-          return oldItem == newItem &&
-                 oldItem.id != selected &&
-                 newItem.id != selected &&
-                 oldItem.id != oldSelected &&
-                 newItem.id != oldSelected
-        }
-      }).dispatchUpdatesTo(this)
-    })
-  }
-
-  private val addListener = {
-    for (addListener in addListeners) {
-      addListener.invoke()
     }
   }
 
-  fun addEditListener(f: (Long) -> Unit) {
+  fun addEditListener(f: (AccountId) -> Unit) {
     actionListeners.add(f)
   }
 
@@ -137,47 +78,30 @@ class AccountAdapter(
     addListeners.add(f)
   }
 
-  fun addSelectionListener(f: (Long) -> Unit) {
-    selectionListeners.add(f)
+  fun addClickListener(f: (AccountId) -> Unit) {
+    clickListeners.add(f)
   }
 
-  override fun onBindViewHolder(holder: AccountViewHolder,
-                                @SuppressLint("RecyclerView") position: Int) {
-    when (holder) {
-      is AccountViewHolder.Item -> {
-        val item = list[position]
-        holder.bind(item.second, item.first)
-      }
-      is AccountViewHolder.Add  -> {
-      }
-    }
+  override fun onBindViewHolder(holder: AccountViewHolder, position: Int) {
+    val (account, selected) = getItem(position)
+    holder.bind(account, selected)
   }
 
-  override fun getItemViewType(position: Int) = when (position) {
-    list.size -> TYPE_ADD
-    else      -> TYPE_ACCOUNT
+  override fun getItemViewType(position: Int) = when (getItem(position).first) {
+    null -> TYPE_ADD
+    else -> TYPE_ACCOUNT
   }
 
-  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountViewHolder {
-    val inflater = LayoutInflater.from(parent.context)
-    val view = inflater.inflate(
-      when (viewType) {
-        TYPE_ADD -> R.layout.widget_core_account_add
-        else     -> R.layout.widget_core_account
-      }, parent, false
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
+    TYPE_ADD -> AccountViewHolder.Add(
+      WidgetCoreAccountAddBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+      addListener
+    )
+    else     -> AccountViewHolder.Item(
+      WidgetCoreAccountBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+      actionListener,
+      clickListener
     )
-    return when (viewType) {
-      TYPE_ADD -> AccountViewHolder.Add(
-        view, addListener
-      )
-      else     -> AccountViewHolder.Item(
-        view, actionListener, clickListener
-      )
-    }
-  }
-
-  override fun getItemCount(): Int {
-    return list.size + 1
   }
 
   companion object {
@@ -185,64 +109,54 @@ class AccountAdapter(
     private const val TYPE_ADD = 1
   }
 
-  fun selectAccount(id: Long) {
-    selectionListener(id)
+  interface ItemListener {
+    fun onAction(id: AccountId, pos: Int)
   }
 
-  interface ItemListener {
-    fun onAction(id: Long, pos: Int)
+  interface AddListener {
+    fun onAction()
   }
 
   sealed class AccountViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    internal var data: Account? = null
-
-    class Item(itemView: View, actionListener: ItemListener, clickListener: ItemListener)
-      : AccountViewHolder(itemView) {
-      @BindView(R.id.account_name)
-      lateinit var accountName: TextView
-
-      @BindView(R.id.account_description)
-      lateinit var accountDescription: TextView
+    abstract fun bind(account: Account?, selected: Boolean)
 
-      @BindView(R.id.account_select)
-      lateinit var accountSelect: AppCompatRadioButton
-
-      @BindView(R.id.account_edit)
-      lateinit var accountEdit: AppCompatImageButton
+    class Item(
+      private val binding: WidgetCoreAccountBinding,
+      actionListener: ItemListener,
+      clickListener: ItemListener
+    ) : AccountViewHolder(binding.root) {
+      private var data: Account? = null
 
       init {
-        ButterKnife.bind(this, itemView)
-        accountEdit.setOnClickListener {
-          actionListener.onAction(data?.id ?: -1L, adapterPosition)
+        binding.accountEdit.setOnClickListener {
+          actionListener.onAction(data?.id ?: AccountId(-1L), adapterPosition)
         }
         itemView.setOnClickListener {
-          clickListener.onAction(data?.id ?: -1L, adapterPosition)
+          clickListener.onAction(data?.id ?: AccountId(-1L), adapterPosition)
         }
       }
 
-      fun bind(account: Account, selected: Boolean) {
+      override fun bind(account: Account?, selected: Boolean) {
         data = account
-        accountName.text = account.name
-        accountDescription.text = itemView.context.resources.getString(
-          R.string.label_user_on_host, account.user, account.host, account.port
+        binding.accountName.text = account?.name
+        binding.accountDescription.text = itemView.context.resources.getString(
+          R.string.label_user_on_host, account?.user, account?.host, account?.port
         )
-        accountSelect.isChecked = selected
-      }
-
-      fun clear() {
-        data = null
-        accountName.text = ""
-        accountDescription.text = ""
-        accountSelect.isChecked = false
+        binding.accountSelect.isChecked = selected
       }
     }
 
-    class Add(itemView: View, clickListener: () -> Unit) : AccountViewHolder(itemView) {
+    class Add(
+      private val binding: WidgetCoreAccountAddBinding,
+      clickListener: AddListener
+    ) : AccountViewHolder(binding.root) {
       init {
         itemView.setOnClickListener {
-          clickListener.invoke()
+          clickListener.onAction()
         }
       }
+
+      override fun bind(account: Account?, selected: Boolean) = Unit
     }
   }
 }
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 b2de628ce0e8a0d966a6a92c4df9cc3764611572..91dac04bed4d585a60b12994547a4ea9d33b95b1 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -31,13 +31,17 @@ import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
+import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.models.Account
+import de.kuschku.quasseldroid.persistence.util.AccountId
 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
 import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActivity.Companion.REQUEST_CREATE_NEW
 import de.kuschku.quasseldroid.ui.setup.accounts.setup.AccountSetupActivity
+import de.kuschku.quasseldroid.util.helper.map
+import de.kuschku.quasseldroid.util.helper.zip
 import javax.inject.Inject
 
 class AccountSelectionSlide : SlideFragment() {
@@ -47,23 +51,26 @@ class AccountSelectionSlide : SlideFragment() {
   @Inject
   lateinit var accountViewModel: AccountViewModel
 
-  override fun isValid() = adapter?.selectedItemId ?: -1L != -1L
+  override fun isValid() = accountViewModel.selectedItem.value?.isValidId() == true
 
   override val title = R.string.slide_account_select_title
   override val description = R.string.slide_account_select_description
 
   override fun setData(data: Bundle) {
-    if (data.containsKey("selectedAccount"))
-      adapter?.selectAccount(data.getLong("selectedAccount"))
+    if (data.containsKey("selectedAccount")) {
+      accountViewModel.selectedItem.postValue(AccountId(data.getLong("selectedAccount")))
+    }
   }
 
   override fun getData(data: Bundle) {
-    data.putLong("selectedAccount", adapter?.selectedItemId ?: -1L)
+    data.putLong("selectedAccount", accountViewModel.selectedItem.value?.id ?: -1L)
   }
 
-  private var adapter: AccountAdapter? = null
+  private val adapter = AccountAdapter()
+
   override fun onCreateContent(inflater: LayoutInflater, container: ViewGroup?,
                                savedInstanceState: Bundle?): View {
+    BufferId
     val view = inflater.inflate(R.layout.setup_select_account, container, false)
     ButterKnife.bind(this, view)
     val firstObserver = object : Observer<List<Account>?> {
@@ -79,10 +86,6 @@ class AccountSelectionSlide : SlideFragment() {
     accountViewModel.accounts.observe(this, firstObserver)
     accountList.layoutManager = LinearLayoutManager(context)
     accountList.itemAnimator = DefaultItemAnimator()
-    val adapter = AccountAdapter(
-      this, accountViewModel.accounts, accountViewModel.selectedItem
-    )
-    this.adapter = adapter
     accountList.adapter = adapter
 
     adapter.addAddListener {
@@ -91,10 +94,16 @@ class AccountSelectionSlide : SlideFragment() {
     adapter.addEditListener { id ->
       startActivityForResult(AccountEditActivity.intent(requireContext(), id), REQUEST_CREATE_NEW)
     }
-    adapter.addSelectionListener {
+    adapter.addClickListener {
       updateValidity()
     }
 
+    accountViewModel.accounts.zip(accountViewModel.selectedItem).map { (accounts, selected) ->
+      accounts.map { Pair(it, it.id == selected) }
+    }.observe(this, Observer {
+      adapter.submitList((it ?: emptyList()) + Pair(null, false))
+    })
+
     return view
   }
 
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 f3ca61e38c5aebfe1ed5e38d184bb4cb3a7a3234..881cc936f5441ec0cc33ec752f52a2211e89105a 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -25,11 +25,12 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import de.kuschku.quasseldroid.persistence.db.AccountDatabase
 import de.kuschku.quasseldroid.persistence.models.Account
+import de.kuschku.quasseldroid.persistence.util.AccountId
 
 class AccountViewModel(application: Application) : AndroidViewModel(application) {
   private val database: AccountDatabase = AccountDatabase.Creator.init(
     getApplication()
   )
   val accounts: LiveData<List<Account>> = database.accounts().all()
-  val selectedItem = MutableLiveData<Pair<Long, Long>>()
+  val selectedItem = MutableLiveData<AccountId>()
 }
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 8de4b8cadbeedfa935596891669650c91185989e..883b9c3e9cad75119d1602d23fe37a709c98d62e 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -23,8 +23,10 @@ import android.app.Activity
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
+import de.kuschku.quasseldroid.persistence.dao.create
 import de.kuschku.quasseldroid.persistence.db.AccountDatabase
 import de.kuschku.quasseldroid.persistence.models.Account
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import de.kuschku.quasseldroid.ui.setup.SetupActivity
 import de.kuschku.quasseldroid.util.AndroidHandlerThread
 import org.threeten.bp.Instant
@@ -37,8 +39,8 @@ class AccountSetupActivity : SetupActivity() {
   lateinit var database: AccountDatabase
 
   override fun onDone(data: Bundle) {
-    val account = Account(
-      id = 0,
+    val account = Account.of(
+      id = AccountId(-1L),
       host = data.getString("host", ""),
       port = data.getInt("port"),
       requireSsl = data.getBoolean("require_ssl"),
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreBackendAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreBackendAdapter.kt
index 1d8d2456729264ddcb957eaabffb840974e32813..a2969528138022bf8e98dfaf7240800da5fd8893 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreBackendAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/core/CoreBackendAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,16 +20,11 @@
 package de.kuschku.quasseldroid.ui.setup.core
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
-import androidx.appcompat.widget.AppCompatRadioButton
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.coresetup.CoreSetupBackend
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetCoreBackendBinding
 
 class CoreBackendAdapter : RecyclerView.Adapter<CoreBackendAdapter.BackendViewHolder>() {
   private val selectionListeners = mutableSetOf<(CoreSetupBackend) -> Unit>()
@@ -105,29 +100,21 @@ class CoreBackendAdapter : RecyclerView.Adapter<CoreBackendAdapter.BackendViewHo
     holder.bind(item.second, item.first)
   }
 
-  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackendViewHolder {
-    val inflater = LayoutInflater.from(parent.context)
-    val view = inflater.inflate(R.layout.widget_core_backend, parent, false)
-    return BackendViewHolder(view, clickListener)
-  }
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = BackendViewHolder(
+    WidgetCoreBackendBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+    clickListener
+  )
 
   override fun getItemCount() = list.size
 
-  class BackendViewHolder(itemView: View, clickListener: (CoreSetupBackend) -> Unit) :
-    RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.backend_name)
-    lateinit var backendName: TextView
-
-    @BindView(R.id.backend_description)
-    lateinit var backendDescription: TextView
-
-    @BindView(R.id.backend_select)
-    lateinit var backendSelect: AppCompatRadioButton
-
+  class BackendViewHolder(
+    private val binding: WidgetCoreBackendBinding,
+    clickListener: (CoreSetupBackend) -> Unit
+  ) :
+    RecyclerView.ViewHolder(binding.root) {
     private var item: CoreSetupBackend? = null
 
     init {
-      ButterKnife.bind(this, itemView)
       itemView.setOnClickListener {
         item?.let(clickListener)
       }
@@ -135,16 +122,9 @@ class CoreBackendAdapter : RecyclerView.Adapter<CoreBackendAdapter.BackendViewHo
 
     fun bind(backend: CoreSetupBackend, selected: Boolean) {
       item = backend
-      backendName.text = backend.displayName
-      backendDescription.text = backend.description
-      backendSelect.isChecked = selected
-    }
-
-    fun clear() {
-      item = null
-      backendName.text = ""
-      backendDescription.text = ""
-      backendSelect.isChecked = false
+      binding.backendName.text = backend.displayName
+      binding.backendDescription.text = backend.description
+      binding.backendSelect.isChecked = selected
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/user/DefaultNetworkAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/user/DefaultNetworkAdapter.kt
index 9d34f609c0fc22743559626a5618094ccd6feee1..9f8ebb44701c196b310334303afc605b53ec2bcd 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/user/DefaultNetworkAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/user/DefaultNetworkAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,14 +20,11 @@
 package de.kuschku.quasseldroid.ui.setup.user
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.appcompat.widget.ThemedSpinnerAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetSpinnerItemMaterialBinding
 import de.kuschku.quasseldroid.defaults.DefaultNetwork
 import de.kuschku.quasseldroid.defaults.DefaultNetworks
 import de.kuschku.quasseldroid.util.ui.ContextThemeWrapper
@@ -43,16 +40,16 @@ class DefaultNetworkAdapter @Inject constructor(defaultNetworks: DefaultNetworks
   override fun onBindViewHolder(holder: DefaultNetworkViewHolder, position: Int) =
     holder.bind(getItem(position))
 
-  override fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean)
-    : DefaultNetworkViewHolder {
+  override fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean): DefaultNetworkViewHolder {
     val inflater = LayoutInflater.from(
       if (dropDown)
         ContextThemeWrapper(parent.context, dropDownViewTheme)
       else
         parent.context
     )
-    val view = inflater.inflate(R.layout.widget_spinner_item_material, parent, false)
-    return DefaultNetworkViewHolder(view)
+    return DefaultNetworkViewHolder(
+      WidgetSpinnerItemMaterialBinding.inflate(inflater, parent, false)
+    )
   }
 
   override fun getItem(position: Int) = data[position]
@@ -65,18 +62,13 @@ class DefaultNetworkAdapter @Inject constructor(defaultNetworks: DefaultNetworks
 
   override fun getItemId(position: Int) = position.toLong()
 
-  class DefaultNetworkViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(android.R.id.text1)
-    lateinit var text: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class DefaultNetworkViewHolder(
+    private val binding: WidgetSpinnerItemMaterialBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(network: DefaultNetwork?) {
       network?.let {
-        text.text = it.name
-      } ?: text.setText(R.string.label_network_custom)
+        binding.text1.text = it.name
+      } ?: binding.text1.setText(R.string.label_network_custom)
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ShortcutCreationHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ShortcutCreationHelper.kt
index c7b2d883c5f0e316d593679ca98e886c07c3fb9f..77d31d5a1a712245e910dba237a9b3a5906aef3e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/ShortcutCreationHelper.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ShortcutCreationHelper.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -27,7 +27,7 @@ import android.graphics.drawable.Drawable
 import androidx.core.content.pm.ShortcutInfoCompat
 import androidx.core.content.pm.ShortcutManagerCompat
 import androidx.core.graphics.drawable.IconCompat
-import com.bumptech.glide.request.target.SimpleTarget
+import com.bumptech.glide.request.target.CustomTarget
 import com.bumptech.glide.request.transition.Transition
 import de.kuschku.libquassel.protocol.Buffer_Type
 import de.kuschku.libquassel.quassel.BufferInfo
@@ -36,6 +36,7 @@ import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.irc.SenderColorUtil
 import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
 import de.kuschku.quasseldroid.util.avatars.AvatarHelper
@@ -46,9 +47,11 @@ import de.kuschku.quasseldroid.viewmodel.helper.EditorViewModelHelper.Companion.
 object ShortcutCreationHelper {
   fun create(context: Context,
              messageSettings: MessageSettings,
-             accountId: Long,
+             accountId: AccountId,
              info: BufferInfo,
              ircUser: IrcUser? = null) {
+    val bitmapSize = context.resources.getInteger(R.integer.shortcut_image_size)
+
     val callback: (IconCompat) -> Unit = { icon ->
       ShortcutManagerCompat.requestPinShortcut(
         context,
@@ -59,7 +62,7 @@ object ShortcutCreationHelper {
             ChatActivity.intent(
               context,
               bufferId = info.bufferId,
-              accountId = accountId
+              accountId = accountId.id
             ).setAction(Intent.ACTION_VIEW)
           )
           .build(),
@@ -68,7 +71,7 @@ object ShortcutCreationHelper {
     }
 
     val resultAvailable: (Drawable) -> Unit = { resource ->
-      val bitmap = Bitmap.createBitmap(432, 432, Bitmap.Config.ARGB_8888)
+      val bitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888)
       val canvas = Canvas(bitmap)
       resource.setBounds(0, 0, canvas.width, canvas.height)
       resource.draw(canvas)
@@ -103,7 +106,7 @@ object ShortcutCreationHelper {
         .buildRect(initial, senderColor)
 
       val urls = ircUser?.let {
-        AvatarHelper.avatar(messageSettings, it, 432)
+        AvatarHelper.avatar(messageSettings, it, bitmapSize)
       }
 
       if (urls == null || urls.isEmpty()) {
@@ -112,7 +115,7 @@ object ShortcutCreationHelper {
         GlideApp.with(context)
           .loadWithFallbacks(urls)
           ?.placeholder(fallback)
-          ?.into(object : SimpleTarget<Drawable>(432, 432) {
+          ?.into(object : CustomTarget<Drawable>(bitmapSize, bitmapSize) {
             override fun onResourceReady(resource: Drawable,
                                          transition: Transition<in Drawable>?) {
               resultAvailable(resource)
@@ -121,6 +124,10 @@ object ShortcutCreationHelper {
             override fun onLoadFailed(errorDrawable: Drawable?) {
               resultAvailable(errorDrawable!!)
             }
+
+            override fun onLoadCleared(placeholder: Drawable?) {
+              // do nothing, as we’ve already processed the drawable
+            }
           })
       }
     } else {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/backport/DaggerLifecycleService.kt b/app/src/main/java/de/kuschku/quasseldroid/util/backport/DaggerLifecycleService.kt
index f584b2417a6f61c6d158a3419b997b5b489a8549..a3a13b760c572091ac8c9327686d42bf0f9d6192 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/backport/DaggerLifecycleService.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/backport/DaggerLifecycleService.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -19,10 +19,10 @@
 
 package de.kuschku.quasseldroid.util.backport
 
-import androidx.lifecycle.LifecycleService
 import dagger.android.AndroidInjection
+import de.kuschku.quasseldroid.util.compatibility.FixedLifecycleService
 
-abstract class DaggerLifecycleService : LifecycleService() {
+abstract class DaggerLifecycleService : FixedLifecycleService() {
   override fun onCreate() {
     AndroidInjection.inject(this)
     super.onCreate()
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/compatibility/FixedLifecycleService.java b/app/src/main/java/de/kuschku/quasseldroid/util/compatibility/FixedLifecycleService.java
new file mode 100644
index 0000000000000000000000000000000000000000..9fac9df26919a32d811e8b44985871354688e31d
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/compatibility/FixedLifecycleService.java
@@ -0,0 +1,103 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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/>.
+ */
+
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package de.kuschku.quasseldroid.util.compatibility;
+
+import android.annotation.SuppressLint;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.ServiceLifecycleDispatcher;
+
+/**
+ * A Service that is also a {@link LifecycleOwner}.
+ */
+@SuppressLint("Registered")
+public class FixedLifecycleService extends Service implements LifecycleOwner {
+
+  private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);
+
+  @CallSuper
+  @Override
+  public void onCreate() {
+    mDispatcher.onServicePreSuperOnCreate();
+    super.onCreate();
+  }
+
+  @CallSuper
+  @Nullable
+  @Override
+  public IBinder onBind(@Nullable Intent intent) {
+    mDispatcher.onServicePreSuperOnBind();
+    return null;
+  }
+
+  @SuppressWarnings("deprecation")
+  @CallSuper
+  @Override
+  public void onStart(@Nullable Intent intent, int startId) {
+    mDispatcher.onServicePreSuperOnStart();
+    super.onStart(intent, startId);
+  }
+
+  // this method is added only to annotate it with @CallSuper.
+  // In usual service super.onStartCommand is no-op, but in LifecycleService
+  // it results in mDispatcher.onServicePreSuperOnStart() call, because
+  // super.onStartCommand calls onStart().
+  @CallSuper
+  @Override
+  public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
+    return super.onStartCommand(intent, flags, startId);
+  }
+
+  @CallSuper
+  @Override
+  public void onDestroy() {
+    mDispatcher.onServicePreSuperOnDestroy();
+    super.onDestroy();
+  }
+
+  @Override
+  @NonNull
+  public Lifecycle getLifecycle() {
+    return mDispatcher.getLifecycle();
+  }
+}
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 94871dbc37db4ad7e0957d65386e50ed371c59d2..2393a835add88abc1e94341fe685dc75b2714394 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
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,11 +20,12 @@
 package de.kuschku.quasseldroid.util.helper
 
 import de.kuschku.quasseldroid.persistence.dao.AccountDao
+import de.kuschku.quasseldroid.persistence.dao.create
 import de.kuschku.quasseldroid.persistence.models.Account
 
 fun AccountDao.new(vararg entities: Account) {
   val ids = create(*entities)
-  for (i in 0 until entities.size) {
+  for (i in entities.indices) {
     entities[i].id = ids[i]
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/missingfeatures/MissingFeaturesAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/util/missingfeatures/MissingFeaturesAdapter.kt
index b8b32192543b167aeb5fad6284ded038357feca4..3194924c42392e0493e5dc5fa1222dc6b9d74002 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/missingfeatures/MissingFeaturesAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/missingfeatures/MissingFeaturesAdapter.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -20,15 +20,11 @@
 package de.kuschku.quasseldroid.util.missingfeatures
 
 import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListAdapter
 import androidx.recyclerview.widget.RecyclerView
-import butterknife.BindView
-import butterknife.ButterKnife
-import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.databinding.WidgetMissingFeatureBinding
 
 class MissingFeaturesAdapter :
   ListAdapter<MissingFeature, MissingFeaturesAdapter.MissingFeatureViewHolder>(
@@ -41,26 +37,18 @@ class MissingFeaturesAdapter :
     }
   ) {
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MissingFeatureViewHolder(
-    LayoutInflater.from(parent.context).inflate(R.layout.widget_missing_feature, parent, false)
+    WidgetMissingFeatureBinding.inflate(LayoutInflater.from(parent.context), parent, false)
   )
 
   override fun onBindViewHolder(holder: MissingFeatureViewHolder, position: Int) =
     holder.bind(getItem(position))
 
-  class MissingFeatureViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.name)
-    lateinit var name: TextView
-
-    @BindView(R.id.description)
-    lateinit var description: TextView
-
-    init {
-      ButterKnife.bind(this, itemView)
-    }
-
+  class MissingFeatureViewHolder(
+    private val binding: WidgetMissingFeatureBinding
+  ) : RecyclerView.ViewHolder(binding.root) {
     fun bind(item: MissingFeature) {
-      name.text = item.feature.name
-      description.setText(item.description)
+      binding.name.text = item.feature.name
+      binding.description.setText(item.description)
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundActivity.kt
index b9f5211f9305ce222cb666e23a0f58b6a5867021..de466fa46e17bac35d45aeea572b0e5fc2ed7822 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundActivity.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -34,6 +34,7 @@ import de.kuschku.libquassel.util.helper.safeValue
 import de.kuschku.quasseldroid.Backend
 import de.kuschku.quasseldroid.Keys
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import de.kuschku.quasseldroid.settings.ConnectionSettings
 import de.kuschku.quasseldroid.settings.Settings
 import de.kuschku.quasseldroid.util.helper.editCommit
@@ -70,12 +71,12 @@ abstract class ServiceBoundActivity :
     }
   }
 
-  fun connectToAccount(accountId: Long) {
+  fun connectToAccount(accountId: AccountId) {
     getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE).editCommit {
       putBoolean(Keys.Status.reconnect, false)
     }
     getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE).editCommit {
-      putLong(Keys.Status.selectedAccount, accountId)
+      putLong(Keys.Status.selectedAccount, accountId.id)
       putBoolean(Keys.Status.reconnect, true)
     }
   }
@@ -86,7 +87,7 @@ abstract class ServiceBoundActivity :
   @Inject
   lateinit var quasselViewModel: QuasselViewModel
 
-  protected var accountId: Long = -1
+  protected var accountId: AccountId = AccountId(-1L)
 
   override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState)
@@ -143,14 +144,13 @@ abstract class ServiceBoundActivity :
     checkConnection()
 
   protected fun checkConnection() {
-    accountId = getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
-                  ?.getLong(Keys.Status.selectedAccount, -1) ?: -1
+    accountId = AccountId(getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
+                            ?.getLong(Keys.Status.selectedAccount, -1) ?: -1)
 
     val reconnect = sharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE) {
       getBoolean(Keys.Status.reconnect, false)
     }
-    val accountIdValid = accountId != -1L
-    if (!reconnect || !accountIdValid) {
+    if (!reconnect || !accountId.isValidId()) {
       onSelectAccount()
     } else {
       if (!connection.start())
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundFragment.kt
index 9c712a33455b32d9a531011b1bcc47ef8144f6d4..1a30474a47f5b2a516066e4a019ae807a3f160a9 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/service/ServiceBoundFragment.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -26,6 +26,7 @@ import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.helper.safeValue
 import de.kuschku.quasseldroid.Backend
 import de.kuschku.quasseldroid.Keys
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
 import io.reactivex.subjects.BehaviorSubject
 import javax.inject.Inject
@@ -50,11 +51,11 @@ abstract class ServiceBoundFragment : DaggerFragment() {
     }
   }
 
-  protected var accountId: Long = -1
+  protected var accountId = AccountId(-1L)
 
   override fun onCreate(savedInstanceState: Bundle?) {
-    accountId = context?.getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
-                  ?.getLong(Keys.Status.selectedAccount, -1) ?: -1
+    accountId = AccountId(context?.getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
+                            ?.getLong(Keys.Status.selectedAccount, -1) ?: -1)
 
     connection.context = context
     lifecycle.addObserver(connection)
@@ -63,8 +64,8 @@ abstract class ServiceBoundFragment : DaggerFragment() {
 
   override fun onStart() {
     super.onStart()
-    accountId = context?.getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
-                  ?.getLong(Keys.Status.selectedAccount, -1) ?: -1
+    accountId = AccountId(context?.getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
+                            ?.getLong(Keys.Status.selectedAccount, -1) ?: -1)
   }
 
   override fun onDestroy() {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt
index 834e4980ae45acdeaf5c7accf9dba5b199e7992d..4e9e9fdba3858e42d2ab1ef67eba30eb384f108e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -54,7 +54,7 @@ open class RingtonePreference : DialogPreference,
     this(context, null)
 
   constructor(context: Context, attrs: AttributeSet?) :
-    this(context, attrs, R.attr.ringtonePreferenceStyle)
+    this(context, attrs, android.R.attr.ringtonePreferenceStyle)
 
   constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
     this(context, attrs, defStyleAttr, 0)
diff --git a/app/src/main/res/values/ints.xml b/app/src/main/res/values/ints.xml
new file mode 100644
index 0000000000000000000000000000000000000000..98e199b176b4a6e5d88531c27c862ed70b42335d
--- /dev/null
+++ b/app/src/main/res/values/ints.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Quasseldroid - Quassel client for Android
+
+  Copyright (c) 2020 Janne Mareike Koschinski
+  Copyright (c) 2020 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/>.
+  -->
+
+<resources>
+  <integer name="shortcut_image_size">432</integer>
+</resources>
diff --git a/app/src/main/res/values/themes_base.xml b/app/src/main/res/values/themes_base.xml
index b5be66c92ecaeec57ff95225d6e61b9b140ce1c2..15d454569f5c2eb6ad3cfa72fc3573deda8f42f1 100644
--- a/app/src/main/res/values/themes_base.xml
+++ b/app/src/main/res/values/themes_base.xml
@@ -1,8 +1,8 @@
 <!--
   Quasseldroid - Quassel client for Android
 
-  Copyright (c) 2019 Janne Mareike Koschinski
-  Copyright (c) 2019 The Quassel Project
+  Copyright (c) 2020 Janne Mareike Koschinski
+  Copyright (c) 2020 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
@@ -87,7 +87,7 @@
     <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
     <item name="actionBarPopupTheme">@style/Widget.PopupOverlay</item>
 
-    <item name="ringtonePreferenceStyle">@style/Widget.RingtonePreference</item>
+    <item name="android:ringtonePreferenceStyle">@style/Widget.RingtonePreference</item>
 
     <item name="backgroundMenuItem">@drawable/bg_menuitem_dark</item>
     <item name="backgroundMenuItemRounded">@drawable/bg_menuitem_rounded_dark</item>
@@ -136,7 +136,7 @@
     <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
     <item name="actionBarPopupTheme">@style/Widget.PopupOverlay.Light</item>
 
-    <item name="ringtonePreferenceStyle">@style/Widget.RingtonePreference</item>
+    <item name="android:ringtonePreferenceStyle">@style/Widget.RingtonePreference</item>
 
     <item name="backgroundMenuItem">@drawable/bg_menuitem_light</item>
     <item name="backgroundMenuItemRounded">@drawable/bg_menuitem_rounded_light</item>
diff --git a/build.gradle.kts b/build.gradle.kts
index aba1b9de15b7f9efdefd7190286374aa92aed21d..930b49a56908f9e9ddb99e8207133b52b8130fe9 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -25,8 +25,8 @@ buildscript {
     jcenter()
   }
   dependencies {
-    classpath("com.android.tools.build:gradle:3.4.2")
-    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.50")
+    classpath("com.android.tools.build:gradle:3.6.1")
+    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61")
   }
 }
 
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f9ec95f434db0fffd15f500b9c77294439394353..c5052237fa3ea762db4ef9fb2e2f84f8732dd6e0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -18,4 +18,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https://services.gradle.org/distributions/gradle-5.3.1-all.zip
+distributionUrl=https://services.gradle.org/distributions/gradle-5.6.4-all.zip
diff --git a/invokergenerator/build.gradle.kts b/invokergenerator/build.gradle.kts
index 5894f28fc8cf3d21cd8e0d43ed68c73d6b87c737..f261b90d3ef91829d4de3f758bb2005974feb4b6 100644
--- a/invokergenerator/build.gradle.kts
+++ b/invokergenerator/build.gradle.kts
@@ -29,9 +29,9 @@ tasks.withType<KotlinCompile> {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
   implementation(project(":invokerannotations"))
-  implementation("org.jetbrains.kotlin", "kotlin-compiler-embeddable", "1.3.50")
+  implementation("org.jetbrains.kotlin", "kotlin-compiler-embeddable", "1.3.61")
   implementation("com.squareup", "kotlinpoet", "1.3.0")
   implementation("com.google.auto.service:auto-service:1.0-rc6")
   kapt("com.google.auto.service:auto-service:1.0-rc6")
diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts
index a30531f7d715c5b1ff197264737d9ac58331862e..279ac550b11786a9a0b1bcd8f6912572fa62c900 100644
--- a/lib/build.gradle.kts
+++ b/lib/build.gradle.kts
@@ -23,7 +23,7 @@ plugins {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
 
   implementation("androidx.annotation", "annotation", "1.1.0")
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/QType.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/QType.kt
index be241b870d789d306658e3df5970e2a932a8612f..faf831fe3243b9261485c0fbe83cd52916b041a2 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/QType.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/QType.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -25,8 +25,7 @@ enum class QType(val typeName: String, val serializer: Serializer<*>,
                  val type: Type = Type.UserType) {
   BufferId("BufferId", BufferIdSerializer),
   BufferInfo("BufferInfo", BufferInfoSerializer),
-  DccConfig_IpDetectionMode("DccConfig::IpDetectionMode",
-                            DccConfig_IpDetectionModeSerializer),
+  DccConfig_IpDetectionMode("DccConfig::IpDetectionMode", DccConfig_IpDetectionModeSerializer),
   DccConfig_PortSelectionMode("DccConfig::PortSelectionMode",
                               DccConfig_PortSelectionModeSerializer),
   IrcUser("IrcUser", VariantMapSerializer),
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/rxjava/ReusableUnicastSubject.java b/lib/src/main/java/de/kuschku/libquassel/util/rxjava/ReusableUnicastSubject.java
index 38ab36b1d0b5862805b9fbf60c483b7dc7d9bcb7..86c4a242ba0d973e15fb7d17dd9aa564cf9a85fd 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/rxjava/ReusableUnicastSubject.java
+++ b/lib/src/main/java/de/kuschku/libquassel/util/rxjava/ReusableUnicastSubject.java
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -206,7 +206,7 @@ public final class ReusableUnicastSubject<T> extends Subject<T> {
     this.delayError = delayError;
     this.actual = new AtomicReference<>();
     this.once = new AtomicBoolean();
-    this.wip = new ReusableUnicastSubject.UnicastQueueDisposable();
+    this.wip = new ReusableUnicastSubject<T>.UnicastQueueDisposable();
   }
 
   /**
@@ -236,7 +236,7 @@ public final class ReusableUnicastSubject<T> extends Subject<T> {
     this.delayError = delayError;
     this.actual = new AtomicReference<Observer<? super T>>();
     this.once = new AtomicBoolean();
-    this.wip = new ReusableUnicastSubject.UnicastQueueDisposable();
+    this.wip = new ReusableUnicastSubject<T>.UnicastQueueDisposable();
   }
 
   /**
diff --git a/lifecycle-ktx/build.gradle.kts b/lifecycle-ktx/build.gradle.kts
index 04ea573ec3cf5cca194d41221546269c64ff6ec6..552bd4187190415c3c4d1bfbcf8f651aaea8d544 100644
--- a/lifecycle-ktx/build.gradle.kts
+++ b/lifecycle-ktx/build.gradle.kts
@@ -22,7 +22,7 @@ plugins {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
 
   implementation("androidx.annotation", "annotation", "1.1.0")
 
diff --git a/malheur/build.gradle.kts b/malheur/build.gradle.kts
index 239f49c2c8ba2b22411c71d095c7dd268be8ebe2..70914cadc35deceac6d6aa92e747d2684217b0a9 100644
--- a/malheur/build.gradle.kts
+++ b/malheur/build.gradle.kts
@@ -26,7 +26,7 @@ android {
   compileSdkVersion(28)
 
   defaultConfig {
-    minSdkVersion(14)
+    minSdkVersion(20)
     targetSdkVersion(28)
 
     consumerProguardFiles("proguard-rules.pro")
@@ -44,7 +44,7 @@ android {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
 
   implementation("com.google.code.gson", "gson", "2.8.5")
   implementation("androidx.annotation", "annotation", "1.1.0")
diff --git a/persistence/build.gradle.kts b/persistence/build.gradle.kts
index 409b7adf9123f26cd0aab736e01ea5c48c56d309..43dd728e2099b30326392bfbfeb6e98465c2e05a 100644
--- a/persistence/build.gradle.kts
+++ b/persistence/build.gradle.kts
@@ -27,7 +27,7 @@ android {
   compileSdkVersion(28)
 
   defaultConfig {
-    minSdkVersion(16)
+    minSdkVersion(20)
     targetSdkVersion(28)
 
     consumerProguardFiles("proguard-rules.pro")
@@ -51,18 +51,18 @@ android {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
 
   implementation("androidx.appcompat", "appcompat", "1.1.0")
 
-  withVersion("2.2.0-rc01") {
+  withVersion("2.2.5") {
     implementation("androidx.room", "room-runtime", version)
     kapt("androidx.room", "room-compiler", version)
     implementation("androidx.room", "room-rxjava2", version)
     testImplementation("androidx.room", "room-testing", version)
   }
 
-  implementation("androidx.paging", "paging-runtime", "2.1.0")
+  implementation("androidx.paging", "paging-runtime", "2.1.2")
 
   // Utility
   implementation("org.threeten", "threetenbp", "1.4.0", classifier = "no-tzdb")
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
index aa7fc973f40712ae815492364f4e0b7338dd2283..ccc784296df66e0b8fab0a5f5ae57280d93652bd 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/AccountDao.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/AccountDao.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -22,6 +22,7 @@ package de.kuschku.quasseldroid.persistence.dao
 import androidx.lifecycle.LiveData
 import androidx.room.*
 import de.kuschku.quasseldroid.persistence.models.Account
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import io.reactivex.Flowable
 
 @Dao
@@ -30,16 +31,16 @@ interface AccountDao {
   fun save(vararg entities: Account)
 
   @Insert(onConflict = OnConflictStrategy.IGNORE)
-  fun create(vararg entities: Account): Array<Long>
+  fun _create(vararg entities: Account): Array<Long>
 
   @Query("SELECT * FROM account WHERE id = :id")
-  fun findById(id: Long): Account?
+  fun _findById(id: Long): Account?
 
   @Query("SELECT * FROM account WHERE id = :id")
-  fun listen(id: Long): LiveData<Account?>
+  fun _listen(id: Long): LiveData<Account?>
 
   @Query("SELECT IFNULL(t.defaultFiltered, :defaultValue) FROM (SELECT defaultFiltered FROM account WHERE id = :id UNION SELECT NULL ORDER BY defaultFiltered DESC LIMIT 1) t")
-  fun listenDefaultFiltered(id: Long, defaultValue: Int): Flowable<Int>
+  fun _listenDefaultFiltered(id: Long, defaultValue: Int): Flowable<Int>
 
   @Query("SELECT * FROM account ORDER BY lastUsed DESC")
   fun all(): LiveData<List<Account>>
@@ -48,8 +49,24 @@ interface AccountDao {
   fun delete(account: Account)
 
   @Query("UPDATE account SET defaultFiltered = :defaultFiltered WHERE id = :id")
-  fun setFiltered(id: Long, defaultFiltered: Int)
+  fun _setFiltered(id: Long, defaultFiltered: Int)
 
   @Query("DELETE FROM account")
   fun clear()
 }
+
+
+fun AccountDao.create(vararg entities: Account): List<AccountId> =
+  _create(*entities).map(::AccountId)
+
+fun AccountDao.findById(id: AccountId): Account? =
+  _findById(id.id)
+
+fun AccountDao.listen(id: AccountId): LiveData<Account?> =
+  _listen(id.id)
+
+fun AccountDao.listenDefaultFiltered(id: AccountId, defaultValue: Int): Flowable<Int> =
+  _listenDefaultFiltered(id.id, defaultValue)
+
+fun AccountDao.setFiltered(id: AccountId, defaultFiltered: Int) =
+  _setFiltered(id.id, defaultFiltered)
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
index e88c50e4f59ef3d1851d452f390c9927add4c47e..862d4ca5f782c8a91f526a517da26e5e1aac0945 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/FilteredDao.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/dao/FilteredDao.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -28,6 +28,7 @@ import androidx.room.Query
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.BufferId_Type
 import de.kuschku.quasseldroid.persistence.models.Filtered
+import de.kuschku.quasseldroid.persistence.util.AccountId
 import io.reactivex.Flowable
 
 @Dao
@@ -44,36 +45,45 @@ interface FilteredDao {
   @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>>
+  fun _listen(accountId: Long): LiveData<List<Filtered>>
 
   @Query("SELECT * FROM filtered WHERE accountId = :accountId")
-  fun listenRx(accountId: Long): Flowable<List<Filtered>>
+  fun _listenRx(accountId: Long): Flowable<List<Filtered>>
+
+  @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("DELETE FROM filtered")
   fun clear()
 
   @Query("DELETE FROM filtered WHERE accountId = :accountId")
-  fun clear(accountId: Long)
+  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.buffers(accountId: AccountId) =
+  _buffers(accountId.id).map(::BufferId)
+
+inline fun FilteredDao.setFiltered(accountId: AccountId, bufferId: BufferId, filtered: Int) =
+  _setFiltered(accountId.id, bufferId.id, filtered)
+
+inline fun FilteredDao.get(accountId: AccountId, bufferId: BufferId, defaultValue: Int) =
+  _get(accountId.id, bufferId.id, defaultValue)
+
+inline fun FilteredDao.listen(accountId: AccountId) =
+  _listen(accountId.id)
 
-inline fun FilteredDao.setFiltered(accountId: Long, bufferId: BufferId, filtered: Int) =
-  _setFiltered(accountId, bufferId.id, filtered)
+inline fun FilteredDao.listenRx(accountId: AccountId) =
+  _listenRx(accountId.id)
 
-inline fun FilteredDao.get(accountId: Long, bufferId: BufferId, defaultValue: Int) =
-  _get(accountId, bufferId.id, defaultValue)
+inline fun FilteredDao.listen(accountId: AccountId, bufferId: BufferId, defaultValue: Int) =
+  _listen(accountId.id, bufferId.id, defaultValue)
 
-inline fun FilteredDao.listen(accountId: Long, bufferId: BufferId, defaultValue: Int) =
-  _listen(accountId, bufferId.id, defaultValue)
+inline fun FilteredDao.clear(accountId: AccountId) =
+  _clear(accountId.id)
 
-inline fun FilteredDao.clear(accountId: Long, bufferId: BufferId) =
-  _clear(accountId, bufferId.id)
+inline fun FilteredDao.clear(accountId: AccountId, bufferId: BufferId) =
+  _clear(accountId.id, bufferId.id)
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
index c2fa8b60419b628974577e8b0391754ad31c3fed..51b84d242ce6c481662390529112e74db7878eea 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Account.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Account.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -19,13 +19,16 @@
 
 package de.kuschku.quasseldroid.persistence.models
 
+import androidx.room.ColumnInfo
 import androidx.room.Entity
 import androidx.room.PrimaryKey
+import de.kuschku.quasseldroid.persistence.util.AccountId
 
 @Entity(tableName = "Account")
 data class Account(
   @PrimaryKey(autoGenerate = true)
-  var id: Long,
+  @ColumnInfo(name = "id")
+  var rawId: Long,
   var host: String,
   var port: Int,
   var requireSsl: Boolean,
@@ -35,4 +38,36 @@ data class Account(
   var lastUsed: Long,
   var acceptedMissingFeatures: Boolean,
   var defaultFiltered: Int
-)
+) {
+  inline var id
+    get() = AccountId(rawId)
+    set(value) {
+      rawId = value.id
+    }
+
+  companion object {
+    inline fun of(
+      id: AccountId,
+      host: String,
+      port: Int,
+      requireSsl: Boolean,
+      user: String,
+      pass: String,
+      name: String,
+      lastUsed: Long,
+      acceptedMissingFeatures: Boolean,
+      defaultFiltered: Int
+    ) = Account(
+      id.id,
+      host,
+      port,
+      requireSsl,
+      user,
+      pass,
+      name,
+      lastUsed,
+      acceptedMissingFeatures,
+      defaultFiltered
+    )
+  }
+}
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
index ffd755a205e22997b925c54e187dce71e4af505a..3fda2b2fc99cf689828f24aa1cbaa454f32cb168 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Filtered.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/models/Filtered.kt
@@ -1,8 +1,8 @@
 /*
  * Quasseldroid - Quassel client for Android
  *
- * Copyright (c) 2019 Janne Mareike Koschinski
- * Copyright (c) 2019 The Quassel Project
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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
@@ -23,6 +23,7 @@ import androidx.room.ColumnInfo
 import androidx.room.Entity
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.BufferId_Type
+import de.kuschku.quasseldroid.persistence.util.AccountId
 
 @Entity(tableName = "filtered", primaryKeys = ["accountId", "bufferId"])
 data class Filtered(
@@ -36,11 +37,11 @@ data class Filtered(
 
   companion object {
     inline fun of(
-      accountId: Long,
+      accountId: AccountId,
       bufferId: BufferId,
       filtered: Int
     ) = Filtered(
-      accountId,
+      accountId.id,
       bufferId.id,
       filtered
     )
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/AccountId.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/AccountId.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d6cc4d995924fc3f1b993184b29eee14d01995c2
--- /dev/null
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/util/AccountId.kt
@@ -0,0 +1,38 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2020 Janne Mareike Koschinski
+ * Copyright (c) 2020 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.util
+
+import java.io.Serializable
+
+typealias AccountId_Type = Long
+
+inline class AccountId(val id: AccountId_Type) : Comparable<AccountId>, Serializable {
+  override fun compareTo(other: AccountId) = id.compareTo(other.id)
+  inline fun isValidId() = id >= 0
+
+  override fun toString(): String {
+    return "AccountId($id)"
+  }
+
+  companion object {
+    val MIN_VALUE = AccountId(AccountId_Type.MIN_VALUE)
+    val MAX_VALUE = AccountId(AccountId_Type.MAX_VALUE)
+  }
+}
diff --git a/ui_spinner/build.gradle.kts b/ui_spinner/build.gradle.kts
index f64f04c70a456469cafb319bc6937288df4dbe2b..d44f61b855e6e11a400aaafb9f08862893e813e3 100644
--- a/ui_spinner/build.gradle.kts
+++ b/ui_spinner/build.gradle.kts
@@ -26,7 +26,7 @@ android {
   compileSdkVersion(28)
 
   defaultConfig {
-    minSdkVersion(16)
+    minSdkVersion(20)
     targetSdkVersion(28)
 
     consumerProguardFiles("proguard-rules.pro")
@@ -44,6 +44,6 @@ android {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
   implementation("androidx.appcompat", "appcompat", "1.1.0")
 }
diff --git a/viewmodel/build.gradle.kts b/viewmodel/build.gradle.kts
index 5800e98c8a8069802d4c4533e9296d06db0cbc7d..7ae12ace91e74ecdc97860ef282981f9b269cab2 100644
--- a/viewmodel/build.gradle.kts
+++ b/viewmodel/build.gradle.kts
@@ -26,7 +26,7 @@ android {
   compileSdkVersion(28)
 
   defaultConfig {
-    minSdkVersion(16)
+    minSdkVersion(20)
     targetSdkVersion(28)
 
     consumerProguardFiles("proguard-rules.pro")
@@ -44,10 +44,10 @@ android {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.3.50"))
+  implementation(kotlin("stdlib", "1.3.61"))
 
   implementation("androidx.appcompat", "appcompat", "1.1.0")
-  withVersion("2.1.0") {
+  withVersion("2.2.0") {
     implementation("androidx.lifecycle", "lifecycle-extensions", version)
     implementation("androidx.lifecycle", "lifecycle-reactivestreams", version)
   }