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 ea1cfb87b8aec9596bb53940aa80d0fb48d10117..b0b50ffb7e188646c767b600e0a3e97db4003fcd 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
@@ -27,6 +27,8 @@ import de.kuschku.quasseldroid.util.helper.*
 import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
 import de.kuschku.quasseldroid.util.ui.SpanFormatter
 import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
+import io.reactivex.BackpressureStrategy
+import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
 class MessageListFragment : ServiceBoundFragment() {
@@ -163,6 +165,17 @@ class MessageListFragment : ServiceBoundFragment() {
     messageList.itemAnimator = null
     messageList.setItemViewCacheSize(20)
 
+    val senderColors = requireContext().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,
+      R.attr.senderColor8, R.attr.senderColor9, R.attr.senderColorA, R.attr.senderColorB,
+      R.attr.senderColorC, R.attr.senderColorD, R.attr.senderColorE, R.attr.senderColorF
+    ) {
+      IntArray(16) {
+        getColor(it, 0)
+      }
+    }
+
     var isScrolling = false
     messageList.addOnScrollListener(
       object : RecyclerView.OnScrollListener() {
@@ -189,7 +202,6 @@ class MessageListFragment : ServiceBoundFragment() {
                              viewModel.markerLine)
       .toLiveData().switchMapNotNull { (buffer, selected, expanded, markerLine) ->
         database.filtered().listen(accountId, buffer).switchMapNotNull { filtered ->
-
           LivePagedListBuilder(
             database.message().findByBufferIdPagedWithDayChange(buffer, filtered).map {
               DisplayMessage(
@@ -213,7 +225,31 @@ class MessageListFragment : ServiceBoundFragment() {
       database.message().lastMsgId(it)
     }
 
-    viewModel.sessionManager_liveData.zip(lastMessageId).observe(
+    var previousVisible = -1
+    viewModel.buffer.toFlowable(BackpressureStrategy.LATEST).switchMap { buffer ->
+      database.filtered().listenRx(accountId, buffer).switchMap { filtered ->
+        database.message().firstMsgId(buffer).map {
+          Pair(it, database.message().firstVisibleMsgId(buffer, filtered))
+        }
+      }
+    }.distinctUntilChanged()
+      .throttleLast(1, TimeUnit.SECONDS)
+      .toLiveData().observe(this, Observer {
+        runInBackground {
+          val first = it?.first
+          val visible = it?.second ?: -1
+
+          if (first != null) {
+            if (previousVisible == visible) {
+              loadMore()
+            }
+
+            previousVisible = visible
+          }
+        }
+      })
+
+    viewModel.session.toLiveData().zip(lastMessageId).observe(
       this, Observer {
       runInBackground {
         val session = it?.first?.orNull()
diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
index 3f9a80bb92362c04729174751512b926569d39f5..4a302cadbcd021fe5ada329eee6a0d760e9f046f 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
@@ -11,8 +11,10 @@ import android.content.Context
 import android.support.annotation.IntRange
 import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Type
+import de.kuschku.libquassel.protocol.MsgId
 import de.kuschku.quasseldroid.persistence.QuasselDatabase.DatabaseMessage
 import de.kuschku.quasseldroid.persistence.QuasselDatabase.Filtered
+import io.reactivex.Flowable
 import org.threeten.bp.Instant
 
 @Database(entities = [DatabaseMessage::class, Filtered::class], version = 3)
@@ -77,6 +79,12 @@ abstract class QuasselDatabase : RoomDatabase() {
     @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1")
     fun lastMsgId(bufferId: Int): LiveData<DatabaseMessage>
 
+    @Query("SELECT messageId FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC LIMIT 1")
+    fun firstMsgId(bufferId: Int): Flowable<MsgId>
+
+    @Query("SELECT messageId FROM message WHERE bufferId = :bufferId AND type & ~ :type > 0 ORDER BY messageId ASC LIMIT 1")
+    fun firstVisibleMsgId(bufferId: Int, type: Int): MsgId?
+
     @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId ASC LIMIT 1")
     fun findFirstByBufferId(bufferId: Int): DatabaseMessage?
 
@@ -123,6 +131,11 @@ abstract class QuasselDatabase : RoomDatabase() {
     )
     fun listen(accountId: Long, bufferId: Int): LiveData<Int>
 
+    @Query(
+      "SELECT filtered FROM filtered WHERE bufferId = :bufferId AND accountId = :accountId UNION SELECT 0 as filtered ORDER BY filtered DESC LIMIT 1"
+    )
+    fun listenRx(accountId: Long, bufferId: Int): Flowable<Int>
+
     @Query("SELECT * FROM filtered WHERE accountId = :accountId")
     fun listen(accountId: Long): LiveData<List<Filtered>>
 
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 42d72e1277a95769584b78e9730c80f5044f4dc9..260f85978a1b7198edcee15136bdba1f136bbb37 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
@@ -3,6 +3,7 @@ package de.kuschku.quasseldroid.util.helper
 import android.arch.lifecycle.LiveData
 import android.arch.lifecycle.LiveDataReactiveStreams
 import io.reactivex.BackpressureStrategy
+import io.reactivex.Flowable
 import io.reactivex.Observable
 import io.reactivex.ObservableSource
 import io.reactivex.functions.BiFunction
@@ -11,6 +12,8 @@ inline fun <T> Observable<T>.toLiveData(
   strategy: BackpressureStrategy = BackpressureStrategy.LATEST
 ): LiveData<T> = LiveDataReactiveStreams.fromPublisher(toFlowable(strategy))
 
+inline fun <T> Flowable<T>.toLiveData(): LiveData<T> = LiveDataReactiveStreams.fromPublisher(this)
+
 inline fun <reified A, B> combineLatest(
   a: ObservableSource<A>,
   b: ObservableSource<B>