diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DisplayMessage.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DisplayMessage.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ad6401441368012da2f2c5db0e546d7d959975bf
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DisplayMessage.kt
@@ -0,0 +1,20 @@
+package de.kuschku.quasseldroid.ui.chat.messages
+
+import de.kuschku.libquassel.protocol.MsgId
+import de.kuschku.quasseldroid.persistence.QuasselDatabase
+
+data class DisplayMessage(
+  val content: QuasselDatabase.DatabaseMessage,
+  val isSelected: Boolean,
+  val isExpanded: Boolean,
+  val isMarkerLine: Boolean
+) {
+  data class Tag(
+    val id: MsgId,
+    val isSelected: Boolean,
+    val isExpanded: Boolean,
+    val isMarkerLine: Boolean
+  )
+
+  val tag = Tag(content.messageId, isSelected, isExpanded, isMarkerLine)
+}
\ No newline at end of file
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 9f744ce6a7e15f3a8f0d3bd9e448bf2224421bbe..53e801e5b8d62b7e5f09531fe9e0e02d5a929a98 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
@@ -5,26 +5,25 @@ import android.support.v7.util.DiffUtil
 import android.util.LruCache
 import android.view.LayoutInflater
 import android.view.ViewGroup
-import de.kuschku.libquassel.protocol.*
+import de.kuschku.libquassel.protocol.Message_Flag
+import de.kuschku.libquassel.protocol.Message_Flags
+import de.kuschku.libquassel.protocol.Message_Type
+import de.kuschku.libquassel.protocol.Message_Types
 import de.kuschku.libquassel.util.hasFlag
-import de.kuschku.quasseldroid.persistence.QuasselDatabase.DatabaseMessage
 import de.kuschku.quasseldroid.util.helper.getOrPut
 
 class MessageAdapter(
-  private val messageRenderer: MessageRenderer,
-  var markerLinePosition: Pair<MsgId, MsgId>? = null
-) : PagedListAdapter<DatabaseMessage, QuasselMessageViewHolder>(
-  object : DiffUtil.ItemCallback<DatabaseMessage>() {
-    override fun areItemsTheSame(oldItem: DatabaseMessage, newItem: DatabaseMessage) =
-      oldItem.messageId == newItem.messageId
+  private val messageRenderer: MessageRenderer
+) : PagedListAdapter<DisplayMessage, QuasselMessageViewHolder>(
+  object : DiffUtil.ItemCallback<DisplayMessage>() {
+    override fun areItemsTheSame(oldItem: DisplayMessage, newItem: DisplayMessage) =
+      oldItem.content.messageId == newItem.content.messageId
 
-    override fun areContentsTheSame(oldItem: DatabaseMessage, newItem: DatabaseMessage) =
-      oldItem == newItem &&
-      oldItem.messageId != markerLinePosition?.first &&
-      oldItem.messageId != markerLinePosition?.second
+    override fun areContentsTheSame(oldItem: DisplayMessage, newItem: DisplayMessage) =
+      oldItem == newItem
   }) {
 
-  private val messageCache = LruCache<Int, FormattedMessage>(512)
+  private val messageCache = LruCache<DisplayMessage.Tag, FormattedMessage>(512)
 
   fun clearCache() {
     messageCache.evictAll()
@@ -34,24 +33,15 @@ class MessageAdapter(
     getItem(position)?.let {
       messageRenderer.bind(
         holder,
-        if (it.messageId == markerLinePosition?.second || it.messageId == markerLinePosition?.first) {
-          val value = messageRenderer.render(
-            holder.itemView.context, it, markerLinePosition?.second ?: -1
-          )
-          messageCache.put(it.messageId, value)
-          value
-        } else {
-          messageCache.getOrPut(it.messageId) {
-            messageRenderer.render(
-              holder.itemView.context, it, markerLinePosition?.second ?: -1
-            )
-          }
-        })
+        messageCache.getOrPut(it.tag) {
+          messageRenderer.render(holder.itemView.context, it)
+        }
+      )
     }
   }
 
   override fun getItemViewType(position: Int) = getItem(position)?.let {
-    viewType(Message_Flags.of(it.type), Message_Flags.of(it.flag))
+    viewType(Message_Flags.of(it.content.type), Message_Flags.of(it.content.flag))
   } ?: 0
 
   private fun viewType(type: Message_Types, flags: Message_Flags) =
@@ -62,7 +52,7 @@ class MessageAdapter(
     }
 
   override fun getItemId(position: Int): Long {
-    return getItem(position)?.messageId?.toLong() ?: 0L
+    return getItem(position)?.content?.messageId?.toLong() ?: 0L
   }
 
   private fun messageType(viewType: Int): Message_Type? =
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
index bf0625c4bb5554b92cbd3f6f2f8ffa8846dba310..c7565fce76dfaaadd1577ef251b5be06e220183d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
@@ -21,10 +21,7 @@ import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.QuasselDatabase
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.BacklogSettings
-import de.kuschku.quasseldroid.util.helper.invoke
-import de.kuschku.quasseldroid.util.helper.switchMapNotNull
-import de.kuschku.quasseldroid.util.helper.toggle
-import de.kuschku.quasseldroid.util.helper.zip
+import de.kuschku.quasseldroid.util.helper.*
 import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
 import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
 import javax.inject.Inject
@@ -62,9 +59,10 @@ class MessageListFragment : ServiceBoundFragment() {
   }
 
   private val boundaryCallback = object :
-    PagedList.BoundaryCallback<QuasselDatabase.DatabaseMessage>() {
-    override fun onItemAtFrontLoaded(itemAtFront: QuasselDatabase.DatabaseMessage) = Unit
-    override fun onItemAtEndLoaded(itemAtEnd: QuasselDatabase.DatabaseMessage) = loadMore()
+    PagedList.BoundaryCallback<DisplayMessage>() {
+    override fun onItemAtFrontLoaded(itemAtFront: DisplayMessage) = Unit
+    override fun onItemAtEndLoaded(itemAtEnd: DisplayMessage) =
+      loadMore(lastMessageId = itemAtEnd.content.messageId)
   }
 
   override fun onCreateView(
@@ -103,19 +101,30 @@ class MessageListFragment : ServiceBoundFragment() {
         }
       })
 
-    val data = viewModel.buffer_liveData.switchMapNotNull { buffer ->
-      database.filtered().listen(accountId, buffer).switchMapNotNull { filtered ->
-        LivePagedListBuilder(
-          database.message().findByBufferIdPaged(buffer, filtered),
-          PagedList.Config.Builder()
-            .setPageSize(backlogSettings.pageSize)
-            .setPrefetchDistance(backlogSettings.pageSize)
-            .setInitialLoadSizeHint(backlogSettings.pageSize)
-            .setEnablePlaceholders(true)
-            .build()
-        ).setBoundaryCallback(boundaryCallback).build()
+    val data = combineLatest(viewModel.buffer,
+                             viewModel.selectedMessages,
+                             viewModel.expandedMessages,
+                             viewModel.markerLine)
+      .toLiveData().switchMapNotNull { (buffer, selected, expanded, markerLine) ->
+        database.filtered().listen(accountId, buffer).switchMapNotNull { filtered ->
+          LivePagedListBuilder(
+            database.message().findByBufferIdPaged(buffer, filtered).map {
+              DisplayMessage(
+                content = it,
+                isSelected = selected.contains(it.messageId),
+                isExpanded = expanded.contains(it.messageId),
+                isMarkerLine = markerLine.orNull() == it.messageId
+              )
+            },
+            PagedList.Config.Builder()
+              .setPageSize(backlogSettings.pageSize)
+              .setPrefetchDistance(backlogSettings.pageSize)
+              .setInitialLoadSizeHint(backlogSettings.pageSize)
+              .setEnablePlaceholders(true)
+              .build()
+          ).setBoundaryCallback(boundaryCallback).build()
+        }
       }
-    }
 
     val lastMessageId = viewModel.buffer_liveData.switchMapNotNull {
       database.message().lastMsgId(it)
@@ -123,7 +132,6 @@ class MessageListFragment : ServiceBoundFragment() {
 
     viewModel.sessionManager_liveData.zip(lastMessageId).observe(
       this, Observer {
-      val firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition()
       runInBackground {
         val session = it?.first?.orNull()
         val message = it?.second
@@ -135,13 +143,6 @@ class MessageListFragment : ServiceBoundFragment() {
       }
     })
 
-    viewModel.markerLine_liveData.observe(this, Observer {
-      it?.ifPresent {
-        adapter.markerLinePosition = it
-        adapter.notifyDataSetChanged()
-      }
-    })
-
     fun checkScroll() {
       if (linearLayoutManager.findFirstVisibleItemPosition() < 2 && !isScrolling) {
         messageList.scrollToPosition(0)
@@ -156,7 +157,7 @@ class MessageListFragment : ServiceBoundFragment() {
     var lastBuffer = -1
     data.observe(this, Observer { list ->
       val firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition()
-      val firstVisibleMessageId = adapter[firstVisibleItemPosition]?.messageId
+      val firstVisibleMessageId = adapter[firstVisibleItemPosition]?.content?.messageId
       runInBackground {
         activity?.runOnUiThread {
           list?.let(adapter::submitList)
@@ -200,7 +201,7 @@ class MessageListFragment : ServiceBoundFragment() {
   override fun onPause() {
     val previous = lastBuffer
     val firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition()
-    val messageId = adapter[firstVisibleItemPosition]?.messageId
+    val messageId = adapter[firstVisibleItemPosition]?.content?.messageId
     val bufferSyncer = viewModel.session.value?.orNull()?.bufferSyncer
     if (previous != null && messageId != null) {
       bufferSyncer?.requestSetMarkerLine(previous, messageId)
@@ -208,13 +209,13 @@ class MessageListFragment : ServiceBoundFragment() {
     super.onPause()
   }
 
-  private fun loadMore(initial: Boolean = false) {
+  private fun loadMore(initial: Boolean = false, lastMessageId: MsgId? = null) {
     runInBackground {
       viewModel.buffer { bufferId ->
         viewModel.session {
           it.orNull()?.backlogManager?.requestBacklog(
             bufferId = bufferId,
-            last = database.message().findFirstByBufferId(
+            last = lastMessageId ?: database.message().findFirstByBufferId(
               bufferId
             )?.messageId ?: -1,
             limit = if (initial) backlogSettings.initialAmount else backlogSettings.pageSize
@@ -223,4 +224,5 @@ class MessageListFragment : ServiceBoundFragment() {
       }
     }
   }
+
 }
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt
index abfc89b57fba916107393808cf481fd3f2242c59..65179bc540a863e27eb5acf6fbbae1e7e39b533d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageRenderer.kt
@@ -3,17 +3,13 @@ package de.kuschku.quasseldroid.ui.chat.messages
 import android.content.Context
 import android.support.annotation.LayoutRes
 import de.kuschku.libquassel.protocol.Message_Type
-import de.kuschku.libquassel.protocol.MsgId
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
 
 interface MessageRenderer {
   @LayoutRes
   fun layout(type: Message_Type?, hasHighlight: Boolean): Int
 
   fun bind(holder: QuasselMessageViewHolder, message: FormattedMessage)
-  fun render(context: Context,
-             message: QuasselDatabase.DatabaseMessage,
-             markerLine: MsgId): FormattedMessage
+  fun render(context: Context, message: DisplayMessage): FormattedMessage
 
   fun init(viewHolder: QuasselMessageViewHolder,
            messageType: Message_Type?,
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
index 928c8f02641d020715c337960445d86fb056dec8..9716c95ab4fef30299d2c16067777974e9f635ba 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
@@ -12,10 +12,8 @@ import android.util.TypedValue
 import de.kuschku.libquassel.protocol.Message.MessageType.*
 import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Type
-import de.kuschku.libquassel.protocol.MsgId
 import de.kuschku.libquassel.util.hasFlag
 import de.kuschku.quasseldroid.R
-import de.kuschku.quasseldroid.persistence.QuasselDatabase
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.AppearanceSettings.ColorizeNicknamesMode
 import de.kuschku.quasseldroid.settings.AppearanceSettings.ShowPrefixMode
@@ -95,8 +93,7 @@ class QuasselMessageRenderer @Inject constructor(
   }
 
   override fun render(context: Context,
-                      message: QuasselDatabase.DatabaseMessage,
-                      markerLine: MsgId): FormattedMessage {
+                      message: DisplayMessage): FormattedMessage {
     context.theme.styledAttributes(
       R.attr.senderColor0, R.attr.senderColor1, R.attr.senderColor2, R.attr.senderColor3,
       R.attr.senderColor4, R.attr.senderColor5, R.attr.senderColor6, R.attr.senderColor7,
@@ -108,224 +105,224 @@ class QuasselMessageRenderer @Inject constructor(
       }
     }
 
-    val self = Message_Flag.of(message.flag).hasFlag(Message_Flag.Self)
-    val highlight = Message_Flag.of(message.flag).hasFlag(Message_Flag.Highlight)
-    return when (Message_Type.of(message.type).enabledValues().firstOrNull()) {
+    val self = Message_Flag.of(message.content.flag).hasFlag(Message_Flag.Self)
+    val highlight = Message_Flag.of(message.content.flag).hasFlag(Message_Flag.Highlight)
+    return when (Message_Type.of(message.content.type).enabledValues().firstOrNull()) {
       Message_Type.Plain        -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
         SpanFormatter.format(
           context.getString(R.string.message_format_plain),
-          formatPrefix(message.senderPrefixes, highlight),
-          formatNick(message.sender, self, highlight, false),
-          formatContent(context, message.content, highlight)
+          formatPrefix(message.content.senderPrefixes, highlight),
+          formatNick(message.content.sender, self, highlight, false),
+          formatContent(context, message.content.content, highlight)
         ),
-        message.messageId == markerLine
+        message.isMarkerLine
       )
       Message_Type.Action       -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
         SpanFormatter.format(
           context.getString(R.string.message_format_action),
-          formatPrefix(message.senderPrefixes, highlight),
-          formatNick(message.sender, self, highlight, false),
-          formatContent(context, message.content, highlight)
+          formatPrefix(message.content.senderPrefixes, highlight),
+          formatNick(message.content.sender, self, highlight, false),
+          formatContent(context, message.content.content, highlight)
         ),
-        message.messageId == markerLine
+        message.isMarkerLine
       )
       Message_Type.Notice       -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
         SpanFormatter.format(
           context.getString(R.string.message_format_notice),
-          formatPrefix(message.senderPrefixes, highlight),
-          formatNick(message.sender, self, highlight, false),
-          formatContent(context, message.content, highlight)
+          formatPrefix(message.content.senderPrefixes, highlight),
+          formatNick(message.content.sender, self, highlight, false),
+          formatContent(context, message.content.content, highlight)
         ),
-        message.messageId == markerLine
+        message.isMarkerLine
       )
       Message_Type.Nick         -> {
-        val nickSelf = message.sender == message.content || self
+        val nickSelf = message.content.sender == message.content.content || self
         FormattedMessage(
-          message.messageId,
-          timeFormatter.format(message.time.atZone(zoneId)),
+          message.content.messageId,
+          timeFormatter.format(message.content.time.atZone(zoneId)),
           if (nickSelf) {
             SpanFormatter.format(
               context.getString(R.string.message_format_nick_self),
-              formatPrefix(message.senderPrefixes, highlight),
-              formatNick(message.sender, nickSelf, highlight, false)
+              formatPrefix(message.content.senderPrefixes, highlight),
+              formatNick(message.content.sender, nickSelf, highlight, false)
             )
           } else {
             SpanFormatter.format(
               context.getString(R.string.message_format_nick),
-              formatPrefix(message.senderPrefixes, highlight),
-              formatNick(message.sender, nickSelf, highlight, false),
-              formatPrefix(message.senderPrefixes, highlight),
-              formatNick(message.content, nickSelf, highlight, false)
+              formatPrefix(message.content.senderPrefixes, highlight),
+              formatNick(message.content.sender, nickSelf, highlight, false),
+              formatPrefix(message.content.senderPrefixes, highlight),
+              formatNick(message.content.content, nickSelf, highlight, false)
             )
           },
-          message.messageId == markerLine
+          message.isMarkerLine
         )
       }
       Message_Type.Mode         -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
         SpanFormatter.format(
           context.getString(R.string.message_format_mode),
-          message.content,
-          formatPrefix(message.senderPrefixes, highlight),
-          formatNick(message.sender, self, highlight, false)
+          message.content.content,
+          formatPrefix(message.content.senderPrefixes, highlight),
+          formatNick(message.content.sender, self, highlight, false)
         ),
-        message.messageId == markerLine
+        message.isMarkerLine
       )
       Message_Type.Join         -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
         SpanFormatter.format(
           context.getString(R.string.message_format_join),
-          formatPrefix(message.senderPrefixes, highlight),
-          formatNick(message.sender, self, highlight, true),
-          message.content
+          formatPrefix(message.content.senderPrefixes, highlight),
+          formatNick(message.content.sender, self, highlight, true),
+          message.content.content
         ),
-        message.messageId == markerLine
+        message.isMarkerLine
       )
       Message_Type.Part         -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
-        if (message.content.isBlank()) {
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
+        if (message.content.content.isBlank()) {
           SpanFormatter.format(
             context.getString(R.string.message_format_part_1),
-            formatPrefix(message.senderPrefixes, highlight),
-            formatNick(message.sender, self, highlight, true)
+            formatPrefix(message.content.senderPrefixes, highlight),
+            formatNick(message.content.sender, self, highlight, true)
           )
         } else {
           SpanFormatter.format(
             context.getString(R.string.message_format_part_2),
-            formatPrefix(message.senderPrefixes, highlight),
-            formatNick(message.sender, self, highlight, true),
-            formatContent(context, message.content, highlight)
+            formatPrefix(message.content.senderPrefixes, highlight),
+            formatNick(message.content.sender, self, highlight, true),
+            formatContent(context, message.content.content, highlight)
           )
         },
-        message.messageId == markerLine
+        message.isMarkerLine
       )
       Message_Type.Quit         -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
-        if (message.content.isBlank()) {
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
+        if (message.content.content.isBlank()) {
           SpanFormatter.format(
             context.getString(R.string.message_format_quit_1),
-            formatPrefix(message.senderPrefixes, highlight),
-            formatNick(message.sender, self, highlight, true)
+            formatPrefix(message.content.senderPrefixes, highlight),
+            formatNick(message.content.sender, self, highlight, true)
           )
         } else {
           SpanFormatter.format(
             context.getString(R.string.message_format_quit_2),
-            formatPrefix(message.senderPrefixes, highlight),
-            formatNick(message.sender, self, highlight, true),
-            formatContent(context, message.content, highlight)
+            formatPrefix(message.content.senderPrefixes, highlight),
+            formatNick(message.content.sender, self, highlight, true),
+            formatContent(context, message.content.content, highlight)
           )
         },
-        message.messageId == markerLine
+        message.isMarkerLine
       )
       Message_Type.Kick         -> {
-        val (user, reason) = message.content.split(' ', limit = 2) + listOf("", "")
+        val (user, reason) = message.content.content.split(' ', limit = 2) + listOf("", "")
         FormattedMessage(
-          message.messageId,
-          timeFormatter.format(message.time.atZone(zoneId)),
+          message.content.messageId,
+          timeFormatter.format(message.content.time.atZone(zoneId)),
           if (reason.isBlank()) {
             SpanFormatter.format(
               context.getString(R.string.message_format_kick_1),
               formatNick(user, false, highlight, false),
-              formatPrefix(message.senderPrefixes, highlight),
-              formatNick(message.sender, self, highlight, true)
+              formatPrefix(message.content.senderPrefixes, highlight),
+              formatNick(message.content.sender, self, highlight, true)
             )
           } else {
             SpanFormatter.format(
               context.getString(R.string.message_format_kick_2),
               formatNick(user, false, highlight, false),
-              formatPrefix(message.senderPrefixes, highlight),
-              formatNick(message.sender, self, highlight, true),
+              formatPrefix(message.content.senderPrefixes, highlight),
+              formatNick(message.content.sender, self, highlight, true),
               formatContent(context, reason, highlight)
             )
           },
-          message.messageId == markerLine
+          message.isMarkerLine
         )
       }
       Message_Type.Kill         -> {
-        val (user, reason) = message.content.split(' ', limit = 2) + listOf("", "")
+        val (user, reason) = message.content.content.split(' ', limit = 2) + listOf("", "")
         FormattedMessage(
-          message.messageId,
-          timeFormatter.format(message.time.atZone(zoneId)),
+          message.content.messageId,
+          timeFormatter.format(message.content.time.atZone(zoneId)),
           if (reason.isBlank()) {
             SpanFormatter.format(
               context.getString(R.string.message_format_kill_1),
               formatNick(user, false, highlight, false),
-              formatPrefix(message.senderPrefixes, highlight),
-              formatNick(message.sender, self, highlight, true)
+              formatPrefix(message.content.senderPrefixes, highlight),
+              formatNick(message.content.sender, self, highlight, true)
             )
           } else {
             SpanFormatter.format(
               context.getString(R.string.message_format_kill_2),
               formatNick(user, false, highlight, false),
-              formatPrefix(message.senderPrefixes, highlight),
-              formatNick(message.sender, self, highlight, true),
+              formatPrefix(message.content.senderPrefixes, highlight),
+              formatNick(message.content.sender, self, highlight, true),
               formatContent(context, reason, highlight)
             )
           },
-          message.messageId == markerLine
+          message.isMarkerLine
         )
       }
       Message_Type.NetsplitJoin -> {
-        val split = message.content.split("#:#")
+        val split = message.content.content.split("#:#")
         val (server1, server2) = split.last().split(' ')
         val usersAffected = split.size - 1
         FormattedMessage(
-          message.messageId,
-          timeFormatter.format(message.time.atZone(zoneId)),
+          message.content.messageId,
+          timeFormatter.format(message.content.time.atZone(zoneId)),
           context.resources.getQuantityString(
             R.plurals.message_netsplit_join, usersAffected, server1, server2, usersAffected
           ),
-          message.messageId == markerLine
+          message.isMarkerLine
         )
       }
       Message_Type.NetsplitQuit -> {
-        val split = message.content.split("#:#")
+        val split = message.content.content.split("#:#")
         val (server1, server2) = split.last().split(' ')
         val usersAffected = split.size - 1
         FormattedMessage(
-          message.messageId,
-          timeFormatter.format(message.time.atZone(zoneId)),
+          message.content.messageId,
+          timeFormatter.format(message.content.time.atZone(zoneId)),
           context.resources.getQuantityString(
             R.plurals.message_netsplit_quit, usersAffected, server1, server2, usersAffected
           ),
-          message.messageId == markerLine
+          message.isMarkerLine
         )
       }
       Message_Type.Server,
       Message_Type.Info,
       Message_Type.Error        -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
-        formatContent(context, message.content, highlight),
-        message.messageId == markerLine
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
+        formatContent(context, message.content.content, highlight),
+        message.isMarkerLine
       )
       Message_Type.Topic        -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
-        formatContent(context, message.content, highlight),
-        message.messageId == markerLine
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
+        formatContent(context, message.content.content, highlight),
+        message.isMarkerLine
       )
       else                      -> FormattedMessage(
-        message.messageId,
-        timeFormatter.format(message.time.atZone(zoneId)),
+        message.content.messageId,
+        timeFormatter.format(message.content.time.atZone(zoneId)),
         SpanFormatter.format(
           "[%d] %s%s: %s",
-          message.type,
-          formatPrefix(message.senderPrefixes, highlight),
-          formatNick(message.sender, self, highlight, true),
-          message.content
+          message.content.type,
+          formatPrefix(message.content.senderPrefixes, highlight),
+          formatNick(message.content.sender, self, highlight, true),
+          message.content.content
         ),
-        message.messageId == markerLine
+        message.isMarkerLine
       )
     }
   }
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/util/helper/ObservableHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/util/helper/ObservableHelper.kt
index 2e725b3625b3d2084dd9e1a198312d366d4d995d..42d72e1277a95769584b78e9730c80f5044f4dc9 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/util/helper/ObservableHelper.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/util/helper/ObservableHelper.kt
@@ -20,12 +20,37 @@ inline fun <reified A, B, C> combineLatest(
   a: ObservableSource<A>,
   b: ObservableSource<B>,
   c: ObservableSource<C>
-): Observable<Triple<A, B, C>> = Observable.combineLatest(listOf(a, b, c), { (t0, t1, t2) ->
-  Triple(t0, t1, t2) as Triple<A, B, C>
-})
+): Observable<Triple<A, B, C>> = Observable.combineLatest(
+  listOf(a, b, c),
+  { (t0, t1, t2) ->
+    Triple(t0, t1, t2) as Triple<A, B, C>
+  }
+)
+
+inline fun <reified A, B, C, D> combineLatest(
+  a: ObservableSource<A>,
+  b: ObservableSource<B>,
+  c: ObservableSource<C>,
+  d: ObservableSource<D>
+): Observable<Tuple4<A, B, C, D>> = Observable.combineLatest(
+  listOf(a, b, c, d),
+  { (t0, t1, t2, t3) ->
+    Tuple4(t0,
+           t1,
+           t2,
+           t3) as Tuple4<A, B, C, D>
+  }
+)
 
 inline fun <reified T> combineLatest(sources: Iterable<ObservableSource<out T>?>) =
   Observable.combineLatest(sources) { t -> t.toList() as List<T> }
 
 inline operator fun <T, U> Observable<T>.invoke(f: (T) -> U?) =
-  blockingLatest().firstOrNull()?.let(f)
\ No newline at end of file
+  blockingLatest().firstOrNull()?.let(f)
+
+data class Tuple4<out A, out B, out C, out D>(
+  val first: A,
+  val second: B,
+  val third: C,
+  val fourth: D
+)
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
index 9544f2fa70226184c63e33e5194906a01da19a5e..f7088caf186775f06ccad71fc50450e21ba439a7 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
@@ -3,6 +3,7 @@ package de.kuschku.quasseldroid.viewmodel
 import android.arch.lifecycle.ViewModel
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.protocol.MsgId
 import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
@@ -27,6 +28,9 @@ import java.util.concurrent.TimeUnit
 class QuasselViewModel : ViewModel() {
   val backendWrapper = BehaviorSubject.createDefault(Observable.empty<Optional<Backend>>())
 
+  val selectedMessages = BehaviorSubject.createDefault(emptyList<MsgId>())
+  val expandedMessages = BehaviorSubject.createDefault(emptyList<MsgId>())
+
   val buffer = BehaviorSubject.createDefault(-1)
   val buffer_liveData = buffer.toLiveData()
 
@@ -69,8 +73,7 @@ class QuasselViewModel : ViewModel() {
   val markerLine = session.mapSwitchMap { currentSession ->
     buffer.switchMap { currentBuffer ->
       // Get a stream of the latest marker line
-      val raw = currentSession.bufferSyncer?.liveMarkerLine(currentBuffer) ?: Observable.empty()
-      raw.scan(Pair(-1, -1)) { (_, previous), next -> Pair(previous, next) }
+      currentSession.bufferSyncer?.liveMarkerLine(currentBuffer) ?: Observable.empty()
     }
   }
   val markerLine_liveData = markerLine.toLiveData()