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 23cdc5645e5d2d1bde9fb371187471b419224986..de5563cee1ba39c0162ee0549d17af312bd98400 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
@@ -60,7 +60,6 @@ import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
 import de.kuschku.libquassel.util.flag.and
 import de.kuschku.libquassel.util.flag.hasFlag
-import de.kuschku.libquassel.util.flag.minus
 import de.kuschku.libquassel.util.flag.or
 import de.kuschku.libquassel.util.helper.combineLatest
 import de.kuschku.libquassel.util.helper.invoke
@@ -359,41 +358,26 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
       }
     })
 
-    val maxBufferActivity = combineLatest(
-      modelHelper.bufferList,
+    val filtered = combineLatest(
       database.filtered().listenRx(accountId).toObservable().map {
         it.associateBy(Filtered::bufferId, Filtered::filtered)
       },
       accountDatabase.accounts().listenDefaultFiltered(accountId, 0).toObservable()
-    ).map { (info, filteredList, defaultFiltered) ->
-      val (config, bufferList) = info
+    )
 
-      val minimumActivity = config?.minimumActivity()?.enabledValues()?.max()
-                            ?: Buffer_Activity.NoActivity
+    val maxBufferActivity = modelHelper.processRawBufferList(modelHelper.bufferViewConfig,
+                                                             filtered).map { (config, bufferList) ->
+      val minimumActivity: Buffer_Activity = config?.minimumActivity()?.enabledValues()?.max()
+                                             ?: Buffer_Activity.NoActivity
 
-      val maxActivity = bufferList.asSequence().map { props ->
-        val activity = props.activity - Message_Type.of(filteredList[props.info.bufferId]?.toUInt()
-                                                        ?: defaultFiltered?.toUInt()
-                                                        ?: 0u)
-        when {
-          props.highlights > 0                  -> Buffer_Activity.Highlight
-          activity.hasFlag(Message_Type.Plain) ||
-          activity.hasFlag(Message_Type.Notice) ||
-          activity.hasFlag(Message_Type.Action) -> Buffer_Activity.NewMessage
-          activity.isNotEmpty()                 -> Buffer_Activity.OtherActivity
-          else                                  -> Buffer_Activity.NoActivity
-        }
+      val maxActivity: Buffer_Activity = bufferList.mapNotNull {
+        it.bufferActivity.enabledValues().max()
       }.max() ?: Buffer_Activity.NoActivity
 
       val hasNotifications = bufferList.any { props ->
-        val activity = props.activity - Message_Type.of(filteredList[props.info.bufferId]?.toUInt()
-                                                        ?: defaultFiltered?.toUInt()
-                                                        ?: 0u)
         when {
           props.info.type hasFlag Buffer_Type.QueryBuffer   ->
-            activity.hasFlag(Message_Type.Plain) ||
-            activity.hasFlag(Message_Type.Notice) ||
-            activity.hasFlag(Message_Type.Action)
+            props.bufferActivity hasFlag Buffer_Activity.NewMessage
           props.info.type hasFlag Buffer_Type.ChannelBuffer ->
             props.highlights > 0
           else                                              -> false
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 4e9ea04b6b32c08b2e0a2cf42f88c1871f1c9720..720a49cc1859e9bf6fb4beba106f89c39ddeb112 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
@@ -34,6 +34,7 @@ import de.kuschku.libquassel.util.helper.value
 import de.kuschku.quasseldroid.R
 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.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
 import de.kuschku.quasseldroid.ui.chat.buffers.BufferListAdapter
@@ -146,13 +147,16 @@ class ArchiveFragment : ServiceBoundFragment() {
     listPermanently.layoutManager = LinearLayoutManager(listPermanently.context)
     listPermanently.itemAnimator = DefaultItemAnimator()
 
+    val filtered = combineLatest(
+      database.filtered().listenRx(accountId).toObservable().map {
+        it.associateBy(Filtered::bufferId, Filtered::filtered)
+      },
+      accountDatabase.accounts().listenDefaultFiltered(accountId, 0).toObservable()
+    )
+
     fun processArchiveBufferList(bufferListType: BufferHiddenState, showHandle: Boolean) =
-      combineLatest(
-        modelHelper.processArchiveBufferList(bufferListType, showHandle),
-        database.filtered().listenRx(accountId).toObservable(),
-        accountDatabase.accounts().listenDefaultFiltered(accountId, 0).toObservable()
-      ).map { (buffers, filteredList, defaultFiltered) ->
-        bufferPresenter.render(buffers, filteredList, defaultFiltered.toUInt())
+      modelHelper.processArchiveBufferList(bufferListType, showHandle, filtered).map { buffers ->
+        bufferPresenter.render(buffers)
       }
 
     processArchiveBufferList(BufferHiddenState.HIDDEN_TEMPORARY, false)
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 60762a55a99c149f9ebf53654b13628dae97e7b2..6078091b10159ab6a23fe7d6b112c9ce5807a77f 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
@@ -46,6 +46,7 @@ import de.kuschku.quasseldroid.BuildConfig
 import de.kuschku.quasseldroid.R
 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.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
@@ -226,12 +227,15 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
       )
     })
 
-    combineLatest(
-      modelHelper.processedBufferList,
-      database.filtered().listenRx(accountId).toObservable(),
+    val filtered = combineLatest(
+      database.filtered().listenRx(accountId).toObservable().map {
+        it.associateBy(Filtered::bufferId, Filtered::filtered)
+      },
       accountDatabase.accounts().listenDefaultFiltered(accountId, 0).toObservable()
-    ).map { (buffers, filteredList, defaultFiltered) ->
-      bufferPresenter.render(buffers, filteredList, defaultFiltered.toUInt())
+    )
+
+    modelHelper.processChatBufferList(filtered).map { buffers ->
+      bufferPresenter.render(buffers)
     }.toLiveData().observe(this, Observer { processedList ->
       if (hasRestoredChatListState) {
         chatListState = chatList.layoutManager?.onSaveInstanceState()
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/presenter/BufferPresenter.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/presenter/BufferPresenter.kt
index 7777d3499891cd49bd1b6fd94291824b4830d661..61c970bd0cb496793cc030070053d8abd209298e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/ui/presenter/BufferPresenter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/presenter/BufferPresenter.kt
@@ -19,13 +19,8 @@
 
 package de.kuschku.quasseldroid.util.ui.presenter
 
-import de.kuschku.libquassel.protocol.BufferId
-import de.kuschku.libquassel.protocol.Buffer_Activity
 import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.util.flag.hasFlag
-import de.kuschku.libquassel.util.flag.minus
-import de.kuschku.quasseldroid.persistence.models.Filtered
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.ColorContext
@@ -42,30 +37,12 @@ class BufferPresenter @Inject constructor(
   val ircFormatDeserializer: IrcFormatDeserializer,
   val colorContext: ColorContext
 ) {
-  fun render(props: BufferProps,
-             activities: Map<BufferId, UInt>,
-             defaultFiltered: UInt
-  ): BufferProps {
-    val activity = props.activity - (activities[props.info.bufferId]
-                                     ?: defaultFiltered
-                                     ?: 0u)
-
+  fun render(props: BufferProps): BufferProps {
     return props.copy(
-      activity = activity,
       description = ircFormatDeserializer.formatString(
         props.description.toString(),
         colorize = messageSettings.colorizeMirc
       ),
-      bufferActivity = Buffer_Activity.of(
-        when {
-          props.highlights > 0                  -> Buffer_Activity.Highlight
-          activity.hasFlag(Message_Type.Plain) ||
-          activity.hasFlag(Message_Type.Notice) ||
-          activity.hasFlag(Message_Type.Action) -> Buffer_Activity.NewMessage
-          activity.isNotEmpty()                 -> Buffer_Activity.OtherActivity
-          else                                  -> Buffer_Activity.NoActivity
-        }
-      ),
       fallbackDrawable = if (props.info.type.hasFlag(Buffer_Type.QueryBuffer)) {
         props.ircUser?.let {
           val nickName = it.nick()
@@ -90,12 +67,8 @@ class BufferPresenter @Inject constructor(
     )
   }
 
-  fun render(buffers: List<BufferListItem>, filteredList: List<Filtered>, defaultFiltered: UInt) =
+  fun render(buffers: List<BufferListItem>) =
     buffers.map {
-      it.copy(props = render(
-        it.props,
-        filteredList.associate { it.bufferId to it.filtered.toUInt() },
-        defaultFiltered
-      ))
+      it.copy(props = render(it.props))
     }
 }
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ArchiveViewModelHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ArchiveViewModelHelper.kt
index 2f555d87fc78d80d28bd90757054ab34549a287f..08ec7fc989a114e7ea08c2ebca3c706ef96a14ca 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ArchiveViewModelHelper.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ArchiveViewModelHelper.kt
@@ -20,24 +20,13 @@
 package de.kuschku.quasseldroid.viewmodel.helper
 
 import de.kuschku.libquassel.protocol.BufferId
-import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.protocol.Message_Type
-import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
-import de.kuschku.libquassel.quassel.syncables.Network
-import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.libquassel.util.Optional
-import de.kuschku.libquassel.util.flag.hasFlag
-import de.kuschku.libquassel.util.helper.combineLatest
 import de.kuschku.libquassel.util.helper.flatMapSwitchMap
 import de.kuschku.libquassel.util.helper.mapSwitchMap
-import de.kuschku.libquassel.util.helper.safeSwitchMap
-import de.kuschku.libquassel.util.irc.IrcCaseMappers
 import de.kuschku.quasseldroid.viewmodel.ArchiveViewModel
 import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
 import de.kuschku.quasseldroid.viewmodel.data.BufferHiddenState
-import de.kuschku.quasseldroid.viewmodel.data.BufferProps
-import de.kuschku.quasseldroid.viewmodel.data.BufferStatus
 import io.reactivex.Observable
 import javax.inject.Inject
 
@@ -51,128 +40,12 @@ open class ArchiveViewModelHelper @Inject constructor(
     }.mapSwitchMap(BufferViewConfig::liveUpdates)
   }
 
-  fun processBufferList(bufferListType: BufferHiddenState) =
-    combineLatest(connectedSession, bufferViewConfig)
-      .safeSwitchMap { (sessionOptional, configOptional) ->
-        val session = sessionOptional.orNull()
-        val bufferSyncer = session?.bufferSyncer
-        val config = configOptional.orNull()
-        if (bufferSyncer != null && config != null) {
-          session.liveNetworks().safeSwitchMap { networks ->
-            config.liveUpdates()
-              .safeSwitchMap { currentConfig ->
-                combineLatest<Collection<BufferId>>(
-                  listOf(
-                    config.liveBuffers(),
-                    config.liveTemporarilyRemovedBuffers(),
-                    config.liveRemovedBuffers()
-                  )
-                ).safeSwitchMap { (ids, temp, perm) ->
-                  fun missingStatusBuffers(
-                    list: Collection<BufferId>
-                  ): Sequence<Observable<BufferProps>?> {
-                    val buffers = list.asSequence().mapNotNull { id ->
-                      bufferSyncer.bufferInfo(id)
-                    }
-
-                    val totalNetworks = buffers.filter {
-                      !it.type.hasFlag(Buffer_Type.StatusBuffer)
-                    }.map {
-                      it.networkId
-                    }.toList()
-
-                    val availableNetworks = buffers.filter {
-                      it.type.hasFlag(Buffer_Type.StatusBuffer)
-                    }.map {
-                      it.networkId
-                    }.toList()
-
-                    val wantedNetworks = if (!currentConfig.networkId().isValidId()) totalNetworks
-                    else listOf(currentConfig.networkId())
-
-                    val missingNetworks = wantedNetworks - availableNetworks
-
-                    return missingNetworks.asSequence().filter {
-                      !currentConfig.networkId().isValidId() || currentConfig.networkId() == it
-                    }.filter {
-                      currentConfig.allowedBufferTypes().hasFlag(Buffer_Type.StatusBuffer)
-                    }.mapNotNull {
-                      networks[it]
-                    }.filter {
-                      !config.hideInactiveNetworks() || it.isConnected()
-                    }.map<Network, Observable<BufferProps>?> { network ->
-                      network.liveNetworkInfo().safeSwitchMap { networkInfo ->
-                        network.liveConnectionState().map { connectionState ->
-                          BufferProps(
-                            info = BufferInfo(
-                              bufferId = BufferId(-networkInfo.networkId.id),
-                              networkId = networkInfo.networkId,
-                              groupId = 0,
-                              bufferName = networkInfo.networkName,
-                              type = Buffer_Type.of(Buffer_Type.StatusBuffer)
-                            ),
-                            network = networkInfo,
-                            networkConnectionState = connectionState,
-                            bufferStatus = BufferStatus.OFFLINE,
-                            description = "",
-                            activity = Message_Type.of(),
-                            highlights = 0,
-                            hiddenState = BufferHiddenState.VISIBLE
-                          )
-                        }
-                      }
-                    }
-                  }
-
-                  fun transformIds(ids: Collection<BufferId>, state: BufferHiddenState) =
-                    processRawBufferList(ids, state, bufferSyncer, networks, currentConfig) +
-                    missingStatusBuffers(ids)
-
-                  bufferSyncer.liveBufferInfos().safeSwitchMap {
-                    val buffers = when (bufferListType) {
-                      BufferHiddenState.VISIBLE          ->
-                        transformIds(ids, BufferHiddenState.VISIBLE)
-                      BufferHiddenState.HIDDEN_TEMPORARY ->
-                        transformIds(temp - ids, BufferHiddenState.HIDDEN_TEMPORARY)
-                      BufferHiddenState.HIDDEN_PERMANENT ->
-                        transformIds(perm - temp - ids, BufferHiddenState.HIDDEN_PERMANENT)
-                    }
-
-                    combineLatest<BufferProps>(buffers.toList()).map { list ->
-                      Pair<BufferViewConfig?, List<BufferProps>>(
-                        config,
-                        list.asSequence().filter {
-                          !config.hideInactiveNetworks() ||
-                          it.networkConnectionState == INetwork.ConnectionState.Initialized
-                        }.filter {
-                          (!config.hideInactiveBuffers()) ||
-                          it.bufferStatus != BufferStatus.OFFLINE ||
-                          it.info.type.hasFlag(Buffer_Type.StatusBuffer)
-                        }.let {
-                          if (config.sortAlphabetically())
-                            it.sortedBy { IrcCaseMappers.unicode.toLowerCaseNullable(it.info.bufferName) }
-                              .sortedBy { it.matchMode.priority }
-                              .sortedByDescending { it.hiddenState == BufferHiddenState.VISIBLE }
-                          else it
-                        }.distinctBy {
-                          it.info.bufferId
-                        }.toList()
-                      )
-                    }
-                  }
-                }
-              }
-          }
-        } else {
-          Observable.just(Pair<BufferViewConfig?, List<BufferProps>>(null, emptyList()))
-        }
-      }
-
   fun processArchiveBufferList(
     bufferListType: BufferHiddenState,
-    showHandle: Boolean
-  ) = processInternalBufferList(
-    processBufferList(bufferListType),
+    showHandle: Boolean,
+    filtered: Observable<Pair<Map<BufferId, Int>, Int>>
+  ) = filterBufferList(
+    processRawBufferList(bufferViewConfig, filtered, bufferListType = bufferListType),
     when (bufferListType) {
       BufferHiddenState.VISIBLE          -> archive.visibleExpandedNetworks
       BufferHiddenState.HIDDEN_TEMPORARY -> archive.temporarilyExpandedNetworks
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ChatViewModelHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ChatViewModelHelper.kt
index a5ec65d1d22a06908ab0751da873ca7fdf2fbf7e..7dfb92e1473c5748ad1e7d10ee3e6458c55f0a6e 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ChatViewModelHelper.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/ChatViewModelHelper.kt
@@ -21,20 +21,17 @@ package de.kuschku.quasseldroid.viewmodel.helper
 
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
 import de.kuschku.libquassel.quassel.syncables.IrcChannel
 import de.kuschku.libquassel.quassel.syncables.IrcUser
-import de.kuschku.libquassel.quassel.syncables.Network
-import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.helper.*
-import de.kuschku.libquassel.util.irc.IrcCaseMappers
 import de.kuschku.quasseldroid.viewmodel.ChatViewModel
 import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
-import de.kuschku.quasseldroid.viewmodel.data.*
+import de.kuschku.quasseldroid.viewmodel.data.BufferData
+import de.kuschku.quasseldroid.viewmodel.data.IrcUserItem
 import io.reactivex.Observable
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -175,125 +172,10 @@ open class ChatViewModelHelper @Inject constructor(
 
   val selectedBuffer = processSelectedBuffer(chat.selectedBufferId, bufferViewConfig)
 
-  val bufferList: Observable<Pair<BufferViewConfig?, List<BufferProps>>> =
-    combineLatest(connectedSession, bufferViewConfig, chat.showHidden, chat.bufferSearch)
-      .safeSwitchMap { (sessionOptional, configOptional, showHiddenRaw, bufferSearch) ->
-        val session = sessionOptional.orNull()
-        val bufferSyncer = session?.bufferSyncer
-        val showHidden = showHiddenRaw ?: false
-        val config = configOptional.orNull()
-        if (bufferSyncer != null && config != null) {
-          session.liveNetworks().safeSwitchMap { networks ->
-            config.liveUpdates()
-              .safeSwitchMap { currentConfig ->
-                combineLatest<Collection<BufferId>>(
-                  listOf(
-                    config.liveBuffers(),
-                    config.liveTemporarilyRemovedBuffers(),
-                    config.liveRemovedBuffers()
-                  )
-                ).safeSwitchMap { (ids, temp, perm) ->
-                  fun transformIds(ids: Collection<BufferId>, state: BufferHiddenState) =
-                    processRawBufferList(
-                      ids,
-                      state,
-                      bufferSyncer,
-                      networks,
-                      currentConfig,
-                      bufferSearch
-                    )
-
-                  fun missingStatusBuffers(
-                    list: Collection<BufferId>): Sequence<Observable<BufferProps>?> {
-                    val totalNetworks = networks.keys
-                    val wantedNetworks = if (!currentConfig.networkId().isValidId()) totalNetworks
-                    else listOf(currentConfig.networkId())
-
-                    val availableNetworks = list.asSequence().mapNotNull { id ->
-                      bufferSyncer.bufferInfo(id)
-                    }.filter {
-                      it.type.hasFlag(Buffer_Type.StatusBuffer)
-                    }.map {
-                      it.networkId
-                    }
-
-                    val missingNetworks = wantedNetworks - availableNetworks
-
-                    return missingNetworks.asSequence().filter {
-                      !currentConfig.networkId().isValidId() || currentConfig.networkId() == it
-                    }.filter {
-                      currentConfig.allowedBufferTypes().hasFlag(Buffer_Type.StatusBuffer)
-                    }.mapNotNull {
-                      networks[it]
-                    }.filter {
-                      !config.hideInactiveNetworks() || it.isConnected()
-                    }.map<Network, Observable<BufferProps>?> { network ->
-                      network.liveNetworkInfo().safeSwitchMap { networkInfo ->
-                        network.liveConnectionState().map { connectionState ->
-                          BufferProps(
-                            info = BufferInfo(
-                              bufferId = BufferId(-networkInfo.networkId.id),
-                              networkId = networkInfo.networkId,
-                              groupId = 0,
-                              bufferName = networkInfo.networkName,
-                              type = Buffer_Type.of(Buffer_Type.StatusBuffer)
-                            ),
-                            network = networkInfo,
-                            networkConnectionState = connectionState,
-                            bufferStatus = BufferStatus.OFFLINE,
-                            description = "",
-                            activity = Message_Type.of(),
-                            highlights = 0,
-                            hiddenState = BufferHiddenState.VISIBLE
-                          )
-                        }
-                      }
-                    }
-                  }
-
-                  bufferSyncer.liveBufferInfos().safeSwitchMap {
-                    val buffers = if (showHidden || bufferSearch.isNotBlank()) {
-                      transformIds(ids, BufferHiddenState.VISIBLE) +
-                      transformIds(temp - ids, BufferHiddenState.HIDDEN_TEMPORARY) +
-                      transformIds(perm - temp - ids, BufferHiddenState.HIDDEN_PERMANENT) +
-                      missingStatusBuffers(ids + temp + perm)
-                    } else {
-                      transformIds(ids, BufferHiddenState.VISIBLE) +
-                      missingStatusBuffers(ids)
-                    }
-
-                    combineLatest<BufferProps>(buffers.toList()).map { list ->
-                      Pair<BufferViewConfig?, List<BufferProps>>(
-                        config,
-                        list.asSequence().filter {
-                          !config.hideInactiveNetworks() ||
-                          it.networkConnectionState == INetwork.ConnectionState.Initialized
-                        }.filter {
-                          (!config.hideInactiveBuffers()) ||
-                          it.bufferStatus != BufferStatus.OFFLINE ||
-                          it.info.type.hasFlag(Buffer_Type.StatusBuffer)
-                        }.let {
-                          if (config.sortAlphabetically())
-                            it.sortedBy { IrcCaseMappers.unicode.toLowerCaseNullable(it.info.bufferName) }
-                              .sortedBy { it.matchMode.priority }
-                              .sortedByDescending { it.hiddenState == BufferHiddenState.VISIBLE }
-                          else it
-                        }.distinctBy {
-                          it.info.bufferId
-                        }.toList()
-                      )
-                    }
-                  }
-                }
-              }
-          }
-        } else {
-          Observable.just(Pair<BufferViewConfig?, List<BufferProps>>(null, emptyList()))
-        }
-      }
-
-  val processedBufferList = processInternalBufferList(
-    bufferList,
+  fun processChatBufferList(
+    filtered: Observable<Pair<Map<BufferId, Int>, Int>>
+  ) = filterBufferList(
+    processRawBufferList(bufferViewConfig, filtered),
     chat.expandedNetworks,
     chat.selectedBufferId,
     false
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/EditorViewModelHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/EditorViewModelHelper.kt
index e4db3b366ee2af2eab5092ac48375ac6b8fa46a9..9390ec1c82b3018986e105fa66a6b43aaab81167 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/EditorViewModelHelper.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/EditorViewModelHelper.kt
@@ -172,13 +172,15 @@ open class EditorViewModelHelper @Inject constructor(
                   Observable.just(it)
                 }
 
-                processResults(when (lastWord.first.firstOrNull()) {
+                processResults(
+                  when (lastWord.first.firstOrNull()) {
                                  '/'  -> getAliases()
                                  '@'  -> getNicks()
                                  '#'  -> getBuffers()
                                  ':'  -> getEmojis()
                                  else -> getAliases() + getNicks() + getBuffers() + getEmojis()
-                               })
+                  }
+                )
               }
             }
           }
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/QuasselViewModelHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/QuasselViewModelHelper.kt
index dc8c062f210401ad45b071aea0e2357b7c5e6420..f57a19ac525269d17f1be22a3e76ebec65cb91f5 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/QuasselViewModelHelper.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/helper/QuasselViewModelHelper.kt
@@ -21,10 +21,7 @@ package de.kuschku.quasseldroid.viewmodel.helper
 
 import de.kuschku.libquassel.connection.ConnectionState
 import de.kuschku.libquassel.connection.Features
-import de.kuschku.libquassel.protocol.BufferId
-import de.kuschku.libquassel.protocol.Buffer_Activity
-import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.protocol.NetworkId
+import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.*
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
@@ -34,7 +31,9 @@ import de.kuschku.libquassel.ssl.X509Helper
 import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.flag.and
 import de.kuschku.libquassel.util.flag.hasFlag
+import de.kuschku.libquassel.util.flag.minus
 import de.kuschku.libquassel.util.helper.*
+import de.kuschku.libquassel.util.irc.IrcCaseMappers
 import de.kuschku.quasseldroid.Backend
 import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
 import de.kuschku.quasseldroid.viewmodel.data.*
@@ -129,9 +128,16 @@ open class QuasselViewModelHelper @Inject constructor(
     }.orElse(Observable.empty())
   }
 
-  fun processRawBufferList(ids: Collection<BufferId>, state: BufferHiddenState,
-                           bufferSyncer: BufferSyncer, networks: Map<NetworkId, Network>,
-                           currentConfig: BufferViewConfig, bufferSearch: String = "") =
+  fun generateBufferProps(
+    ids: Collection<BufferId>,
+    state: BufferHiddenState,
+    bufferSyncer: BufferSyncer,
+    networks: Map<NetworkId, Network>,
+    currentConfig: BufferViewConfig,
+    filtered: Map<BufferId, Int>,
+    defaultFiltered: Int,
+    bufferSearch: String = ""
+  ) =
     ids.asSequence().mapNotNull { id ->
       bufferSyncer.bufferInfo(id)
     }.filter {
@@ -153,9 +159,9 @@ open class QuasselViewModelHelper @Inject constructor(
     }.map<Pair<BufferInfo, Network>, Observable<BufferProps>?> { (info, network) ->
       bufferSyncer.liveActivity(info.bufferId).safeSwitchMap { activity ->
         bufferSyncer.liveHighlightCount(info.bufferId).map { highlights ->
-          activity to highlights
+          Pair(activity, highlights)
         }
-      }.safeSwitchMap { (activity, highlights) ->
+      }.safeSwitchMap { (rawActivity, highlights) ->
         val name = info.bufferName?.trim() ?: ""
         val search = bufferSearch.trim()
         val matchMode = when {
@@ -163,6 +169,8 @@ open class QuasselViewModelHelper @Inject constructor(
           name.startsWith(search, ignoreCase = true) -> MatchMode.START
           else                                       -> MatchMode.CONTAINS
         }
+        val activity = rawActivity - Message_Type.of(filtered[info.bufferId]?.toUInt()
+                                                     ?: defaultFiltered.toUInt())
         when (info.type.toInt()) {
           BufferInfo.Type.QueryBuffer.toInt()   -> {
             network.liveNetworkInfo().safeSwitchMap { networkInfo ->
@@ -181,6 +189,18 @@ open class QuasselViewModelHelper @Inject constructor(
                       description = user?.realName() ?: "",
                       activity = activity,
                       highlights = highlights,
+                      bufferActivity = when {
+                        highlights > 0                       ->
+                          Buffer_Activity.of(Buffer_Activity.Highlight)
+                        activity hasFlag Message_Type.Plain ||
+                        activity hasFlag Message_Type.Notice ||
+                        activity hasFlag Message_Type.Action ->
+                          Buffer_Activity.of(Buffer_Activity.NewMessage)
+                        activity.isNotEmpty()                ->
+                          Buffer_Activity.of(Buffer_Activity.OtherActivity)
+                        else                                 ->
+                          Buffer_Activity.of(Buffer_Activity.NoActivity)
+                      },
                       hiddenState = state,
                       ircUser = user,
                       matchMode = matchMode
@@ -206,6 +226,18 @@ open class QuasselViewModelHelper @Inject constructor(
                       description = it?.topic() ?: "",
                       activity = activity,
                       highlights = highlights,
+                      bufferActivity = when {
+                        highlights > 0                       ->
+                          Buffer_Activity.of(Buffer_Activity.Highlight)
+                        activity hasFlag Message_Type.Plain ||
+                        activity hasFlag Message_Type.Notice ||
+                        activity hasFlag Message_Type.Action ->
+                          Buffer_Activity.of(Buffer_Activity.NewMessage)
+                        activity.isNotEmpty()                ->
+                          Buffer_Activity.of(Buffer_Activity.OtherActivity)
+                        else                                 ->
+                          Buffer_Activity.of(Buffer_Activity.NoActivity)
+                      },
                       hiddenState = state,
                       matchMode = matchMode
                     )
@@ -225,6 +257,18 @@ open class QuasselViewModelHelper @Inject constructor(
                   description = "",
                   activity = activity,
                   highlights = highlights,
+                  bufferActivity = when {
+                    highlights > 0                       ->
+                      Buffer_Activity.of(Buffer_Activity.Highlight)
+                    activity hasFlag Message_Type.Plain ||
+                    activity hasFlag Message_Type.Notice ||
+                    activity hasFlag Message_Type.Action ->
+                      Buffer_Activity.of(Buffer_Activity.NewMessage)
+                    activity.isNotEmpty()                ->
+                      Buffer_Activity.of(Buffer_Activity.OtherActivity)
+                    else                                 ->
+                      Buffer_Activity.of(Buffer_Activity.NoActivity)
+                  },
                   hiddenState = state,
                   matchMode = matchMode
                 )
@@ -236,7 +280,138 @@ open class QuasselViewModelHelper @Inject constructor(
       }
     }
 
-  fun processInternalBufferList(
+  fun processRawBufferList(
+    bufferViewConfig: Observable<Optional<BufferViewConfig>>,
+    filteredTypes: Observable<Pair<Map<BufferId, Int>, Int>>,
+    bufferSearch: Observable<String> = Observable.just(""),
+    bufferListType: BufferHiddenState = BufferHiddenState.VISIBLE
+  ): Observable<Pair<BufferViewConfig?, List<BufferProps>>> =
+    combineLatest(connectedSession, bufferViewConfig, filteredTypes, bufferSearch)
+      .safeSwitchMap { (sessionOptional, configOptional, rawFiltered, bufferSearch) ->
+        val session = sessionOptional.orNull()
+        val bufferSyncer = session?.bufferSyncer
+        val config = configOptional.orNull()
+        val (filtered, defaultFiltered) = rawFiltered
+        if (bufferSyncer != null && config != null) {
+          session.liveNetworks().safeSwitchMap { networks ->
+            config.liveUpdates()
+              .safeSwitchMap { currentConfig ->
+                combineLatest<Collection<BufferId>>(
+                  listOf(
+                    config.liveBuffers(),
+                    config.liveTemporarilyRemovedBuffers(),
+                    config.liveRemovedBuffers()
+                  )
+                ).safeSwitchMap { (ids, temp, perm) ->
+                  fun transformIds(ids: Collection<BufferId>, state: BufferHiddenState) =
+                    generateBufferProps(
+                      ids,
+                      state,
+                      bufferSyncer,
+                      networks,
+                      currentConfig,
+                      filtered,
+                      defaultFiltered,
+                      bufferSearch
+                    )
+
+                  fun missingStatusBuffers(
+                    list: Collection<BufferId>): Sequence<Observable<BufferProps>?> {
+                    val totalNetworks = networks.keys
+                    val wantedNetworks = if (!currentConfig.networkId().isValidId()) totalNetworks
+                    else listOf(currentConfig.networkId())
+
+                    val availableNetworks = list.asSequence().mapNotNull { id ->
+                      bufferSyncer.bufferInfo(id)
+                    }.filter {
+                      it.type.hasFlag(Buffer_Type.StatusBuffer)
+                    }.map {
+                      it.networkId
+                    }
+
+                    val missingNetworks = wantedNetworks - availableNetworks
+
+                    return missingNetworks.asSequence().filter {
+                      !currentConfig.networkId().isValidId() || currentConfig.networkId() == it
+                    }.filter {
+                      currentConfig.allowedBufferTypes().hasFlag(Buffer_Type.StatusBuffer)
+                    }.mapNotNull {
+                      networks[it]
+                    }.filter {
+                      !config.hideInactiveNetworks() || it.isConnected()
+                    }.map<Network, Observable<BufferProps>?> { network ->
+                      network.liveNetworkInfo().safeSwitchMap { networkInfo ->
+                        network.liveConnectionState().map { connectionState ->
+                          BufferProps(
+                            info = BufferInfo(
+                              bufferId = BufferId(-networkInfo.networkId.id),
+                              networkId = networkInfo.networkId,
+                              groupId = 0,
+                              bufferName = networkInfo.networkName,
+                              type = Buffer_Type.of(Buffer_Type.StatusBuffer)
+                            ),
+                            network = networkInfo,
+                            networkConnectionState = connectionState,
+                            bufferStatus = BufferStatus.OFFLINE,
+                            description = "",
+                            activity = Message_Type.of(),
+                            highlights = 0,
+                            hiddenState = BufferHiddenState.VISIBLE
+                          )
+                        }
+                      }
+                    }
+                  }
+
+                  bufferSyncer.liveBufferInfos().safeSwitchMap {
+                    val buffers = if (bufferSearch.isNotBlank()) {
+                      transformIds(ids, BufferHiddenState.VISIBLE) +
+                      transformIds(temp - ids, BufferHiddenState.HIDDEN_TEMPORARY) +
+                      transformIds(perm - temp - ids, BufferHiddenState.HIDDEN_PERMANENT) +
+                      missingStatusBuffers(ids + temp + perm)
+                    } else when (bufferListType) {
+                      BufferHiddenState.VISIBLE          ->
+                        transformIds(ids, BufferHiddenState.VISIBLE) +
+                        missingStatusBuffers(ids)
+                      BufferHiddenState.HIDDEN_TEMPORARY ->
+                        transformIds(temp - ids, BufferHiddenState.HIDDEN_TEMPORARY) +
+                        missingStatusBuffers(temp - ids)
+                      BufferHiddenState.HIDDEN_PERMANENT ->
+                        transformIds(perm - temp - ids, BufferHiddenState.HIDDEN_PERMANENT) +
+                        missingStatusBuffers(perm - temp - ids)
+                    }
+
+                    combineLatest<BufferProps>(buffers.toList()).map { list ->
+                      Pair<BufferViewConfig?, List<BufferProps>>(
+                        config,
+                        list.asSequence().filter {
+                          !config.hideInactiveNetworks() ||
+                          it.networkConnectionState == INetwork.ConnectionState.Initialized
+                        }.filter {
+                          (!config.hideInactiveBuffers()) ||
+                          it.bufferStatus != BufferStatus.OFFLINE ||
+                          it.info.type.hasFlag(Buffer_Type.StatusBuffer)
+                        }.let {
+                          if (config.sortAlphabetically())
+                            it.sortedBy { IrcCaseMappers.unicode.toLowerCaseNullable(it.info.bufferName) }
+                              .sortedBy { it.matchMode.priority }
+                              .sortedByDescending { it.hiddenState == BufferHiddenState.VISIBLE }
+                          else it
+                        }.distinctBy {
+                          it.info.bufferId
+                        }.toList()
+                      )
+                    }
+                  }
+                }
+              }
+          }
+        } else {
+          Observable.just(Pair<BufferViewConfig?, List<BufferProps>>(null, emptyList()))
+        }
+      }
+
+  fun filterBufferList(
     buffers: Observable<Pair<BufferViewConfig?, List<BufferProps>>>,
     expandedNetworks: Observable<Map<NetworkId, Boolean>>,
     selected: Observable<BufferId>,