diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferListAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..388691cea9255c689c428d7d1641a172f439f0d3
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferListAdapter.kt
@@ -0,0 +1,71 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+import android.arch.lifecycle.LifecycleOwner
+import android.arch.lifecycle.LiveData
+import android.arch.lifecycle.Observer
+import android.support.v7.util.DiffUtil
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import butterknife.BindView
+import butterknife.ButterKnife
+import de.kuschku.libquassel.protocol.BufferId
+
+class BufferListAdapter(
+  lifecycleOwner: LifecycleOwner,
+  liveData: LiveData<List<BufferId>?>,
+  runInBackground: (() -> Unit) -> Any,
+  runOnUiThread: (Runnable) -> Any
+) : RecyclerView.Adapter<BufferListAdapter.BufferViewHolder>() {
+  var data = mutableListOf<BufferId>()
+
+  init {
+    liveData.observe(lifecycleOwner, Observer { list: List<BufferId>? ->
+      runInBackground {
+        val old = data
+        val new = list ?: emptyList()
+        val result = DiffUtil.calculateDiff(
+          object : DiffUtil.Callback() {
+            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int)
+              = old[oldItemPosition] == new[newItemPosition]
+
+            override fun getOldListSize() = old.size
+            override fun getNewListSize() = new.size
+
+            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int)
+              = old[oldItemPosition] == new[newItemPosition]
+          }, true)
+        runOnUiThread(Runnable {
+          data.clear()
+          data.addAll(new)
+          result.dispatchUpdatesTo(this@BufferListAdapter)
+        })
+      }
+    })
+  }
+
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = BufferViewHolder(
+    LayoutInflater.from(parent.context)
+      .inflate(android.R.layout.simple_list_item_1, parent, false)
+  )
+
+  override fun onBindViewHolder(holder: BufferViewHolder, position: Int)
+    = holder.bind(data[position])
+
+  override fun getItemCount() = data.size
+
+  class BufferViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+    @BindView(android.R.id.text1)
+    lateinit var text: TextView
+
+    init {
+      ButterKnife.bind(this, itemView)
+    }
+
+    fun bind(bufferId: BufferId) {
+      text.text = "$bufferId"
+    }
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..007573f626c2546f8f88cbdbc9b46a9ef0688edd
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigAdapter.kt
@@ -0,0 +1,76 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+import android.arch.lifecycle.LifecycleOwner
+import android.arch.lifecycle.LiveData
+import android.arch.lifecycle.Observer
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.ThemedSpinnerAdapter
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import butterknife.BindView
+import butterknife.ButterKnife
+import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
+import de.kuschku.quasseldroid_ng.R
+import de.kuschku.quasseldroid_ng.util.ui.ContextThemeWrapper
+import de.kuschku.quasseldroid_ng.util.ui.RecyclerSpinnerAdapter
+
+class BufferViewConfigAdapter(
+  lifecycleOwner: LifecycleOwner,
+  liveData: LiveData<List<BufferViewConfig>>
+) : RecyclerSpinnerAdapter<BufferViewConfigAdapter.BufferViewConfigViewHolder>(),
+    ThemedSpinnerAdapter {
+  val data = mutableListOf<BufferViewConfig>()
+
+  init {
+    liveData.observe(lifecycleOwner, Observer { list: List<BufferViewConfig>? ->
+      data.clear()
+      if (list != null) {
+        data.addAll(list)
+      }
+      notifyDataSetChanged()
+    })
+  }
+
+  override fun isEmpty() = data.isEmpty()
+
+  override fun onBindViewHolder(holder: BufferViewConfigViewHolder, position: Int)
+    = holder.bind(getItem(position))
+
+  override fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean)
+    : BufferViewConfigViewHolder {
+    val inflater = LayoutInflater.from(
+      if (dropDown)
+        ContextThemeWrapper(parent.context, dropDownViewTheme)
+      else
+        parent.context
+    )
+    val view = inflater.inflate(R.layout.widget_spinner_item_toolbar, parent, false)
+    return BufferViewConfigViewHolder(view)
+  }
+
+  override fun getItem(position: Int): BufferViewConfig? = when (position) {
+    in (0 until data.size) -> data[position]
+    else                   -> null
+  }
+
+  override fun getItemId(position: Int) = getItem(position)?.bufferViewId()?.toLong() ?: -1L
+
+  override fun hasStableIds() = true
+
+  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)
+    }
+
+    fun bind(bufferViewConfig: BufferViewConfig?) {
+      text.text = bufferViewConfig?.bufferViewName() ?: ""
+    }
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
index 1357f85f23066bea3c707dbffe08c70757e9c868..ba7818a4fc59b58ef8e7f2a422560b0524bf1931 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
@@ -14,8 +14,10 @@ import android.widget.Button
 import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
-import de.kuschku.libquassel.quassel.syncables.BufferViewManager
-import de.kuschku.libquassel.session.*
+import de.kuschku.libquassel.session.Backend
+import de.kuschku.libquassel.session.ConnectionState
+import de.kuschku.libquassel.session.SessionManager
+import de.kuschku.libquassel.session.SocketAddress
 import de.kuschku.libquassel.util.compatibility.LoggingHandler
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
 import de.kuschku.quasseldroid_ng.Keys
@@ -46,16 +48,6 @@ class ChatActivity : ServiceBoundActivity() {
   private val sessionManager: LiveData<SessionManager?> = backend.map(Backend::sessionManager)
   private val state = sessionManager.switchMapRx(SessionManager::state)
 
-  private val bufferViewManager: LiveData<BufferViewManager?>
-    = sessionManager.switchMapRx(SessionManager::session).map(ISession::bufferViewManager)
-  private val bufferViewConfigs = bufferViewManager.switchMapRx { manager ->
-    manager.bufferViewConfigIds.map { ids ->
-      ids.map { id ->
-        manager.bufferViewConfig(id)
-      }.sortedBy { it?.bufferViewName() }
-    }
-  }
-
   private var snackbar: Snackbar? = null
 
   private val dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ISO_TIME
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListDelegate.kt
deleted file mode 100644
index 13a9fa6662bd17ef7e6b37e906d23eb000ede531..0000000000000000000000000000000000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListDelegate.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.kuschku.quasseldroid_ng.ui.chat
-
-class ChatListDelegate
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d128a9486337a97815466df9e729b5587d99f6a5
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListFragment.kt
@@ -0,0 +1,90 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+import android.arch.lifecycle.LiveData
+import android.arch.lifecycle.MutableLiveData
+import android.os.Bundle
+import android.support.v7.widget.*
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.AdapterView
+import butterknife.BindView
+import butterknife.ButterKnife
+import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
+import de.kuschku.libquassel.quassel.syncables.BufferViewManager
+import de.kuschku.libquassel.session.Backend
+import de.kuschku.libquassel.session.ISession
+import de.kuschku.libquassel.session.SessionManager
+import de.kuschku.quasseldroid_ng.R
+import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
+import de.kuschku.quasseldroid_ng.util.helper.map
+import de.kuschku.quasseldroid_ng.util.helper.or
+import de.kuschku.quasseldroid_ng.util.helper.switchMapRx
+import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment
+
+class ChatListFragment : ServiceBoundFragment() {
+  private val handlerThread = AndroidHandlerThread("ChatList")
+
+  @BindView(R.id.chatListToolbar)
+  lateinit var chatListToolbar: Toolbar
+
+  @BindView(R.id.chatListSpinner)
+  lateinit var chatListSpinner: AppCompatSpinner
+
+  @BindView(R.id.chatList)
+  lateinit var chatList: RecyclerView
+
+  private val sessionManager: LiveData<SessionManager?>
+    = backend.map(Backend::sessionManager)
+  private val bufferViewManager: LiveData<BufferViewManager?>
+    = sessionManager.switchMapRx(SessionManager::session).map(ISession::bufferViewManager)
+  private val bufferViewConfigs = bufferViewManager.switchMapRx { manager ->
+    manager.live_bufferViewConfigs.map { ids ->
+      ids.mapNotNull { id ->
+        manager.bufferViewConfig(id)
+      }.sortedWith(Comparator { a, b ->
+        (a?.bufferViewName() ?: "").compareTo((b?.bufferViewName() ?: ""), true)
+      })
+    }
+  }.or(emptyList())
+
+  private val selectedBufferViewConfig = MutableLiveData<BufferViewConfig>()
+
+  private val itemSelectedListener = object : AdapterView.OnItemSelectedListener {
+    override fun onNothingSelected(p0: AdapterView<*>?) {
+      selectedBufferViewConfig.value = null
+    }
+
+    override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
+      selectedBufferViewConfig.value = adapter.getItem(p2)
+    }
+  }
+
+  private val adapter = BufferViewConfigAdapter(this, bufferViewConfigs)
+
+  private val bufferList = selectedBufferViewConfig.switchMapRx(BufferViewConfig::live_buffers)
+
+  override fun onCreate(savedInstanceState: Bundle?) {
+    handlerThread.onCreate()
+    super.onCreate(savedInstanceState)
+  }
+
+  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+                            savedInstanceState: Bundle?): View? {
+    val view = inflater.inflate(R.layout.content_chat_list, container, false)
+    ButterKnife.bind(this, view)
+    chatListSpinner.adapter = adapter
+    chatListSpinner.onItemSelectedListener = itemSelectedListener
+
+    chatList.adapter = BufferListAdapter(this, bufferList, handlerThread::post,
+                                         activity::runOnUiThread)
+    chatList.layoutManager = LinearLayoutManager(context)
+    chatList.itemAnimator = DefaultItemAnimator()
+    return view
+  }
+
+  override fun onDestroy() {
+    handlerThread.onDestroy()
+    super.onDestroy()
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/EditorDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/EditorDelegate.kt
deleted file mode 100644
index 936c10251e84a1613110a19f9c5a174f13c91005..0000000000000000000000000000000000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/EditorDelegate.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.kuschku.quasseldroid_ng.ui.chat
-
-class EditorDelegate
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListDelegate.kt
deleted file mode 100644
index 1bb9509be2604a846961ea10d958e0caff38ef7f..0000000000000000000000000000000000000000
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListDelegate.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.kuschku.quasseldroid_ng.ui.chat
-
-class NickListDelegate
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt
index ce4bdbb4ea6f51b98c1625becced4d00d597a44c..1d68c90a2b4e233318ee45eb64145bd84897b4d2 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt
@@ -28,6 +28,10 @@ class AccountAdapter :
     }
   }
 
+  init {
+    setHasStableIds(true)
+  }
+
   private val actionListener = object : ItemListener {
     override fun onAction(id: Long, pos: Int) {
       for (actionListener in actionListeners) {
@@ -77,8 +81,8 @@ class AccountAdapter :
     selectionListeners.remove(f)
   }
 
-  override fun onBindViewHolder(holder: AccountViewHolder, @SuppressLint(
-    "RecyclerView") position: Int) {
+  override fun onBindViewHolder(holder: AccountViewHolder,
+                                @SuppressLint("RecyclerView") position: Int) {
     when (holder) {
       is AccountViewHolder.Item -> {
         val account = getItem(position)
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt
index ddfdb78758459205cc02f5356b764d9dc05e4920..8b0f9998205dfe8c2285b74dcb1ed6b44ab1002e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt
@@ -90,7 +90,7 @@ inline fun <X> LiveData<X>.orElse(
 }
 
 @MainThread
-inline fun <X> LiveData<X>.or(
+inline fun <X> LiveData<X?>.or(
   default: X
 ): LiveData<X> {
   val result = object : MediatorLiveData<X>() {
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..87c260f11ad0bbbb6047a1306d7c26acc1bb1269
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt
@@ -0,0 +1,49 @@
+package de.kuschku.quasseldroid_ng.util.service
+
+import android.arch.lifecycle.MutableLiveData
+import android.content.ComponentName
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.Bundle
+import android.os.IBinder
+import android.support.v4.app.Fragment
+import de.kuschku.libquassel.session.Backend
+import de.kuschku.quasseldroid_ng.service.QuasselService
+
+abstract class ServiceBoundFragment : Fragment() {
+  protected val backend = MutableLiveData<Backend?>()
+
+  private val connection = object : ServiceConnection {
+    override fun onServiceDisconnected(component: ComponentName?) {
+      when (component) {
+        ComponentName(context.applicationContext, QuasselService::class.java) -> {
+          backend.value = null
+        }
+      }
+    }
+
+    override fun onServiceConnected(component: ComponentName?, binder: IBinder?) {
+      when (component) {
+        ComponentName(context.applicationContext, QuasselService::class.java) ->
+          if (binder is QuasselService.QuasselBinder) {
+            backend.value = binder.backend
+          }
+      }
+    }
+  }
+
+  override fun onCreate(savedInstanceState: Bundle?) {
+    super.onCreate(savedInstanceState)
+    context.startService(Intent(context, QuasselService::class.java))
+  }
+
+  override fun onStart() {
+    context.bindService(Intent(context, QuasselService::class.java), connection, 0)
+    super.onStart()
+  }
+
+  override fun onStop() {
+    super.onStop()
+    context.unbindService(connection)
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/ContextThemeWrapper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/ContextThemeWrapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..39996a3caaa0b0d9734cc0c0b59ed4935d58dd6c
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/ContextThemeWrapper.kt
@@ -0,0 +1,177 @@
+package de.kuschku.quasseldroid_ng.util.ui
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.res.AssetManager
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.os.Build
+import android.support.annotation.StyleRes
+import android.support.v7.appcompat.R
+import android.view.LayoutInflater
+
+/**
+ * A ContextWrapper that allows you to modify the theme from what is in the
+ * wrapped context.
+ *
+ * @hide
+ */
+class ContextThemeWrapper : ContextWrapper {
+  var themeResId: Int = 0
+    private set
+  private var mTheme: Resources.Theme? = null
+  private var mInflater: LayoutInflater? = null
+  /**
+   * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
+   * callbacks.
+   * @hide
+   */
+  var overrideConfiguration: Configuration? = null
+    private set
+  private var mResources: Resources? = null
+
+  /**
+   * Creates a new context wrapper with no theme and no base context.
+   *
+   *
+   * **Note:** A base context **must** be attached
+   * using [.attachBaseContext] before calling any other
+   * method on the newly constructed context wrapper.
+   */
+  constructor() : super(null)
+
+  /**
+   * Creates a new context wrapper with the specified theme.
+   *
+   *
+   * The specified theme will be applied on top of the base context's theme.
+   * Any attributes not explicitly defined in the theme identified by
+   * <var>themeResId</var> will retain their original values.
+   *
+   * @param base the base context
+   * @param themeResId the resource ID of the theme to be applied on top of
+   * the base context's theme
+   */
+  constructor(base: Context, @StyleRes themeResId: Int) : super(base) {
+    this.themeResId = themeResId
+  }
+
+  /**
+   * Creates a new context wrapper with the specified theme.
+   *
+   *
+   * Unlike [.ContextThemeWrapper], the theme passed to
+   * this constructor will completely replace the base context's theme.
+   *
+   * @param base the base context
+   * @param theme the theme against which resources should be inflated
+   */
+  constructor(base: Context, theme: Resources.Theme?) : super(base) {
+    mTheme = theme
+  }
+
+  override fun attachBaseContext(newBase: Context) {
+    super.attachBaseContext(newBase)
+  }
+
+  /**
+   * Call to set an "override configuration" on this context -- this is
+   * a configuration that replies one or more values of the standard
+   * configuration that is applied to the context.  See
+   * [Context.createConfigurationContext] for more
+   * information.
+   *
+   *
+   * This method can only be called once, and must be called before any
+   * calls to [.getResources] or [.getAssets] are made.
+   */
+  fun applyOverrideConfiguration(overrideConfiguration: Configuration) {
+    if (mResources != null) {
+      throw IllegalStateException(
+        "getResources() or getAssets() has already been called")
+    }
+    if (this.overrideConfiguration != null) {
+      throw IllegalStateException("Override configuration has already been set")
+    }
+    this.overrideConfiguration = Configuration(overrideConfiguration)
+  }
+
+  override fun getResources(): Resources? {
+    return resourcesInternal
+  }
+
+  private val resourcesInternal: Resources?
+    get() {
+      if (mResources == null) {
+        if (overrideConfiguration == null) {
+          mResources = super.getResources()
+        } else if (Build.VERSION.SDK_INT >= 17) {
+          val resContext = createConfigurationContext(overrideConfiguration)
+          mResources = resContext.resources
+        }
+      }
+      return mResources
+    }
+
+  override fun setTheme(resid: Int) {
+    if (themeResId != resid) {
+      themeResId = resid
+      initializeTheme()
+    }
+  }
+
+  override fun getTheme(): Resources.Theme? {
+    if (mTheme != null) {
+      return mTheme
+    }
+
+    if (themeResId == 0) {
+      themeResId = R.style.Theme_AppCompat_Light
+    }
+    initializeTheme()
+
+    return mTheme
+  }
+
+  override fun getSystemService(name: String): Any? {
+    if (Context.LAYOUT_INFLATER_SERVICE == name) {
+      if (mInflater == null) {
+        mInflater = LayoutInflater.from(baseContext).cloneInContext(this)
+      }
+      return mInflater
+    }
+    return baseContext.getSystemService(name)
+  }
+
+  /**
+   * Called by [.setTheme] and [.getTheme] to apply a theme
+   * resource to the current Theme object.  Can override to change the
+   * default (simple) behavior.  This method will not be called in multiple
+   * threads simultaneously.
+   *
+   * @param theme The Theme object being modified.
+   * @param resid The theme style resource being applied to <var>theme</var>.
+   * @param first Set to true if this is the first time a style is being
+   * applied to <var>theme</var>.
+   */
+  protected fun onApplyThemeResource(theme: Resources.Theme, resid: Int, first: Boolean) {
+    theme.applyStyle(resid, true)
+  }
+
+  private fun initializeTheme() {
+    val first = mTheme == null
+    if (first) {
+      mTheme = resources!!.newTheme()
+      val theme = baseContext.theme
+      if (theme != null) {
+        mTheme!!.setTo(theme)
+      }
+    }
+    onApplyThemeResource(mTheme!!, themeResId, first)
+  }
+
+  override fun getAssets(): AssetManager {
+    // Ensure we're returning assets with the correct configuration.
+    return resources!!.assets
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/RecyclerSpinnerAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/RecyclerSpinnerAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..368b5c791598241bfc240be2b9ca2608e69d6ea0
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/RecyclerSpinnerAdapter.kt
@@ -0,0 +1,37 @@
+package de.kuschku.quasseldroid_ng.util.ui
+
+import android.content.res.Resources
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.ThemedSpinnerAdapter
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+
+abstract class RecyclerSpinnerAdapter<VH : RecyclerView.ViewHolder> : BaseAdapter(),
+                                                                      ThemedSpinnerAdapter {
+  private var dropDownViewTheme: Resources.Theme? = null
+  override fun getDropDownViewTheme() = dropDownViewTheme
+  override fun setDropDownViewTheme(theme: Resources.Theme?) {
+    dropDownViewTheme = theme
+  }
+
+  override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
+    val tag = convertView?.tag
+    val holder: VH = tag as? VH ?: onCreateViewHolder(parent, true)
+    holder.itemView.tag = holder
+    onBindViewHolder(holder, position)
+    return holder.itemView
+  }
+
+  override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+    val tag = convertView?.tag
+    val holder = tag as? VH ?: onCreateViewHolder(parent, false)
+    holder.itemView.tag = holder
+    onBindViewHolder(holder, position)
+    return holder.itemView
+  }
+
+
+  protected abstract fun onBindViewHolder(holder: VH, position: Int)
+  protected abstract fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean): VH
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index f81b88965a24284ac96c715cfc4b775626643783..0c505022b8b5aca928d6c2617ec12b1fac38a367 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -22,7 +22,8 @@
         android:layout_width="match_parent"
         android:layout_height="?attr/actionBarSize"
         android:background="?attr/colorPrimary"
-        app:contentInsetStartWithNavigation="0dp">
+        app:contentInsetStartWithNavigation="0dp"
+        app:popupTheme="@style/Widget.PopupOverlay">
 
         <LinearLayout
           android:id="@+id/toolbar_action_area"
@@ -89,5 +90,18 @@
 
   <include layout="@layout/content_nick_list" />
 
-  <include layout="@layout/content_chat_list" />
+  <de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="start"
+    android:background="?android:attr/windowBackground"
+    android:fitsSystemWindows="true"
+    app:insetForeground="?attr/colorPrimaryDark">
+
+    <fragment
+      android:id="@+id/chatListFragment"
+      android:name="de.kuschku.quasseldroid_ng.ui.chat.ChatListFragment"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent" />
+  </de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout>
 </android.support.v4.widget.DrawerLayout>
diff --git a/app/src/main/res/layout/content_chat_list.xml b/app/src/main/res/layout/content_chat_list.xml
index 7c7cba9cb62882854db66a64d1f46edb328558bb..a5bf5a98ef227351033b387322190ebf47cd8bae 100644
--- a/app/src/main/res/layout/content_chat_list.xml
+++ b/app/src/main/res/layout/content_chat_list.xml
@@ -1,45 +1,37 @@
-<de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
-  xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
-  android:layout_gravity="start"
-  android:background="?android:attr/windowBackground"
-  android:fitsSystemWindows="true"
-  app:insetForeground="?attr/colorPrimaryDark"
-  tools:showIn="@layout/activity_main">
+  android:orientation="vertical">
 
-  <LinearLayout
+  <android.support.design.widget.AppBarLayout
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:layout_height="wrap_content"
+    android:theme="?attr/actionBarTheme">
 
-    <android.support.design.widget.AppBarLayout
+    <android.support.v7.widget.Toolbar
+      android:id="@+id/chatListToolbar"
       android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:theme="?attr/actionBarTheme">
+      android:layout_height="?attr/actionBarSize"
+      android:background="?attr/colorPrimary"
+      android:theme="?attr/actionBarTheme"
+      app:contentInsetStartWithNavigation="0dp"
+      app:popupTheme="@style/Widget.PopupOverlay">
 
-      <android.support.v7.widget.Toolbar
-        android:id="@+id/chatListToolbar"
-        android:layout_width="match_parent"
-        android:layout_height="?attr/actionBarSize"
-        android:background="?attr/colorPrimary"
-        app:contentInsetStartWithNavigation="0dp">
+      <android.support.v7.widget.AppCompatSpinner
+        android:id="@+id/chatListSpinner"
+        android:layout_width="fill_parent"
+        android:layout_height="match_parent"
+        android:theme="?attr/actionBarTheme"
+        app:popupTheme="@style/Widget.PopupOverlay" />
 
-        <android.support.v7.widget.AppCompatSpinner
-          android:id="@+id/chatListSpinner"
-          android:layout_width="fill_parent"
-          android:layout_height="match_parent"
-          android:theme="?attr/actionBarTheme" />
+    </android.support.v7.widget.Toolbar>
 
-      </android.support.v7.widget.Toolbar>
+  </android.support.design.widget.AppBarLayout>
 
-    </android.support.design.widget.AppBarLayout>
 
-
-    <android.support.v7.widget.RecyclerView
-      android:id="@+id/chatList"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent" />
-  </LinearLayout>
-</de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout>
+  <android.support.v7.widget.RecyclerView
+    android:id="@+id/chatList"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_spinner_item_inline.xml b/app/src/main/res/layout/widget_spinner_item_inline.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b21fc81584630bf85d2771c9dd2c164f7013e61c
--- /dev/null
+++ b/app/src/main/res/layout/widget_spinner_item_inline.xml
@@ -0,0 +1,7 @@
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+  android:id="@android:id/text1"
+  android:layout_width="match_parent"
+  android:layout_height="wrap_content"
+  android:gravity="center_vertical"
+  android:minHeight="48dp"
+  android:textAppearance="?android:attr/textAppearanceListItemSmall" />
diff --git a/app/src/main/res/layout/widget_spinner_item_toolbar.xml b/app/src/main/res/layout/widget_spinner_item_toolbar.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fa2ad16dc1baf60651bce7e96127b01ba6600e77
--- /dev/null
+++ b/app/src/main/res/layout/widget_spinner_item_toolbar.xml
@@ -0,0 +1,11 @@
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:tools="http://schemas.android.com/tools"
+  android:id="@android:id/text1"
+  android:layout_width="match_parent"
+  android:layout_height="wrap_content"
+  android:gravity="center_vertical"
+  android:minHeight="?attr/actionBarSize"
+  android:paddingLeft="16dp"
+  android:paddingRight="16dp"
+  android:textAppearance="?android:attr/textAppearanceListItemSmall"
+  tools:text="All Chats" />
diff --git a/app/src/main/res/values/styles_widgets.xml b/app/src/main/res/values/styles_widgets.xml
index f10b077c7d58296629c4a67f69298a5ab73e4da8..7c72974099ec0791346f033dd16aa62775e7d814 100644
--- a/app/src/main/res/values/styles_widgets.xml
+++ b/app/src/main/res/values/styles_widgets.xml
@@ -35,4 +35,6 @@
   <style name="Widget.DrawerArrowToggle.Light" parent="Widget.AppCompat.DrawerArrowToggle">
     <item name="color">?attr/colorControlNormal</item>
   </style>
+
+  <style name="Widget.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
 </resources>
diff --git a/app/src/main/res/values/themes_base.xml b/app/src/main/res/values/themes_base.xml
index 1929c6d5a5bb2291628cb0523db12e4901735fe0..9ca5f8a3c00abd278ac97f5fb1bd4bde883c3f61 100644
--- a/app/src/main/res/values/themes_base.xml
+++ b/app/src/main/res/values/themes_base.xml
@@ -12,16 +12,14 @@
     <item name="colorAccent">@color/colorAccent</item>
   </style>
 
-  <style name="Theme.AppTheme.Light.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
-    <item name="colorPrimary">@color/colorPrimary</item>
-    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
-    <item name="colorAccent">@color/colorAccent</item>
+  <style name="Theme.AppTheme.NoActionBar" parent="Theme.AppTheme">
+    <item name="windowActionBar">false</item>
+    <item name="windowNoTitle">true</item>
   </style>
 
-  <style name="Theme.AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar">
-    <item name="colorPrimary">@color/colorPrimary</item>
-    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
-    <item name="colorAccent">@color/colorAccent</item>
+  <style name="Theme.AppTheme.Light.NoActionBar" parent="Theme.AppTheme.Light">
+    <item name="windowActionBar">false</item>
+    <item name="windowNoTitle">true</item>
   </style>
 
   <style name="Theme.Base.ChatTheme" parent="Theme.AppTheme.NoActionBar" />
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt
index e96c1a90b933d65a84b3b0caeecd17698a1fe52e..2ed66474cf78211ba3089cb39fb58f4884cb4083 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt
@@ -5,6 +5,7 @@ import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.protocol.Type
 import de.kuschku.libquassel.quassel.syncables.interfaces.IBufferViewConfig
 import de.kuschku.libquassel.session.SignalProxy
+import io.reactivex.subjects.BehaviorSubject
 
 class BufferViewConfig constructor(
   bufferViewId: Int,
@@ -54,14 +55,17 @@ class BufferViewConfig constructor(
 
   override fun initSetBufferList(buffers: QVariantList) {
     _buffers = buffers.mapNotNull { it.value<BufferId?>() }.toMutableList()
+    live_buffers.onNext(_buffers)
   }
 
   override fun initSetRemovedBuffers(buffers: QVariantList) {
     _removedBuffers = buffers.mapNotNull { it.value<BufferId?>() }.toMutableSet()
+    live_removedBuffers.onNext(_removedBuffers)
   }
 
   override fun initSetTemporarilyRemovedBuffers(buffers: QVariantList) {
     _temporarilyRemovedBuffers = buffers.mapNotNull { it.value<BufferId?>() }.toMutableSet()
+    live_temporarilyRemovedBuffers.onNext(_temporarilyRemovedBuffers)
   }
 
   override fun initSetProperties(properties: QVariantMap) {
@@ -82,13 +86,18 @@ class BufferViewConfig constructor(
     if (_buffers.contains(bufferId))
       return
 
-    if (_removedBuffers.contains(bufferId))
+    if (_removedBuffers.contains(bufferId)) {
       _removedBuffers.remove(bufferId)
+      live_removedBuffers.onNext(_removedBuffers)
+    }
 
-    if (_temporarilyRemovedBuffers.contains(bufferId))
+    if (_temporarilyRemovedBuffers.contains(bufferId)) {
       _temporarilyRemovedBuffers.remove(bufferId)
+      live_temporarilyRemovedBuffers.onNext(_temporarilyRemovedBuffers)
+    }
 
     _buffers.add(minOf(maxOf(pos, 0), _buffers.size), bufferId)
+    live_buffers.onNext(_buffers)
   }
 
   override fun moveBuffer(bufferId: BufferId, pos: Int) {
@@ -107,26 +116,38 @@ class BufferViewConfig constructor(
       _buffers.removeAt(currentPos)
       _buffers.add(bufferId, targetPos - 1)
     }
+
+    live_buffers.onNext(_buffers)
   }
 
   override fun removeBuffer(bufferId: BufferId) {
-    if (_buffers.contains(bufferId))
+    if (_buffers.contains(bufferId)) {
       _buffers.remove(bufferId)
+      live_buffers.onNext(_buffers)
+    }
 
-    if (_removedBuffers.contains(bufferId))
+    if (_removedBuffers.contains(bufferId)) {
       _removedBuffers.remove(bufferId)
+      live_removedBuffers.onNext(_removedBuffers)
+    }
 
     _temporarilyRemovedBuffers.add(bufferId)
+    live_temporarilyRemovedBuffers.onNext(_temporarilyRemovedBuffers)
   }
 
   override fun removeBufferPermanently(bufferId: BufferId) {
-    if (_buffers.contains(bufferId))
+    if (_buffers.contains(bufferId)) {
       _buffers.remove(bufferId)
+      live_buffers.onNext(_buffers)
+    }
 
-    if (_temporarilyRemovedBuffers.contains(bufferId))
+    if (_temporarilyRemovedBuffers.contains(bufferId)) {
       _temporarilyRemovedBuffers.remove(bufferId)
+      live_temporarilyRemovedBuffers.onNext(_temporarilyRemovedBuffers)
+    }
 
     _removedBuffers.add(bufferId)
+    live_removedBuffers.onNext(_removedBuffers)
   }
 
   fun bufferViewId() = _bufferViewId
@@ -206,4 +227,13 @@ class BufferViewConfig constructor(
   private var _buffers: MutableList<BufferId> = mutableListOf()
   private var _removedBuffers: MutableSet<BufferId> = mutableSetOf()
   private var _temporarilyRemovedBuffers: MutableSet<BufferId> = mutableSetOf()
+
+  val live_buffers: BehaviorSubject<List<BufferId>>
+    = BehaviorSubject.createDefault<List<BufferId>>(emptyList())
+
+  val live_removedBuffers: BehaviorSubject<Set<BufferId>>
+    = BehaviorSubject.createDefault<Set<BufferId>>(emptySet())
+
+  val live_temporarilyRemovedBuffers: BehaviorSubject<Set<BufferId>>
+    = BehaviorSubject.createDefault<Set<BufferId>>(emptySet())
 }
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt
index 101b215a48068c5443dc781699f283a6beaf2888..0de820eb5943b7459ef44a715b3502f21abcb848 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt
@@ -36,7 +36,7 @@ class BufferViewManager constructor(
 
     proxy.synchronize(config, !initialized)
     _bufferViewConfigs[config.bufferViewId()] = config
-    bufferViewConfigIds.onNext(_bufferViewConfigs.keys)
+    live_bufferViewConfigs.onNext(_bufferViewConfigs.keys)
   }
 
   override fun addBufferViewConfig(bufferViewConfigId: Int) {
@@ -51,12 +51,12 @@ class BufferViewManager constructor(
       return
 
     _bufferViewConfigs.remove(bufferViewConfigId)
-    bufferViewConfigIds.onNext(_bufferViewConfigs.keys)
+    live_bufferViewConfigs.onNext(_bufferViewConfigs.keys)
   }
 
   private val _bufferViewConfigs: MutableMap<Int, BufferViewConfig>
     = mutableMapOf()
 
-  val bufferViewConfigIds: BehaviorSubject<Set<Int>>
+  val live_bufferViewConfigs: BehaviorSubject<Set<Int>>
     = BehaviorSubject.createDefault<Set<Int>>(emptySet())
 }