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 3623247e33477574a980a196fe9a1cd44f4fd275..938998a313e77df8d8879533026f1219411641fa 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
@@ -115,6 +115,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
 
     editor = Editor(
       this,
+      viewModel.rawAutoCompleteData,
       viewModel.autoCompleteData,
       viewModel.lastWord,
       findViewById(R.id.chatline),
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt
index d3a9f21fb2d0ff810360e848f05c68c80fa36539..02dfc3fa2212eb339d1c11134a2c5980f2da6c99 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt
@@ -17,7 +17,12 @@ import android.view.*
 import android.view.inputmethod.EditorInfo
 import butterknife.BindView
 import butterknife.ButterKnife
+import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.quassel.syncables.IrcChannel
+import de.kuschku.libquassel.session.ISession
 import de.kuschku.libquassel.util.IrcUserUtils
+import de.kuschku.libquassel.util.Optional
+import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.helpers.value
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.settings.AppearanceSettings
@@ -30,14 +35,15 @@ import de.kuschku.quasseldroid.util.ui.ColorChooserDialog
 import de.kuschku.quasseldroid.util.ui.EditTextSelectionChange
 import de.kuschku.quasseldroid.util.ui.TextDrawable
 import de.kuschku.quasseldroid.viewmodel.data.AutoCompleteItem
+import de.kuschku.quasseldroid.viewmodel.data.BufferStatus
 import io.reactivex.Observable
 import io.reactivex.subjects.BehaviorSubject
-import java.util.concurrent.TimeUnit
 
 class Editor(
   // Contexts
   activity: AppCompatActivity,
   // LiveData
+  private val autoCompleteDataRaw: Observable<Triple<Optional<ISession>, Int, Pair<String, IntRange>>>,
   private val autoCompleteData: Observable<Pair<String, List<AutoCompleteItem>>>,
   lastWordContainer: BehaviorSubject<Observable<Pair<String, IntRange>>>,
   // Views
@@ -165,8 +171,7 @@ class Editor(
       formatHandler::autoComplete
     )
 
-    autoCompleteData.debounce(300, TimeUnit.MILLISECONDS)
-      .toLiveData().observe(activity, Observer {
+    autoCompleteData.toLiveData().observe(activity, Observer {
         val query = it?.first ?: ""
         val shouldShowResults = (autoCompleteSettings.auto && query.length >= 3) ||
                                 (autoCompleteSettings.prefix && query.startsWith('@')) ||
@@ -452,12 +457,79 @@ class Editor(
     chatline.setSelection(selectionStart, selectionEnd)
   }
 
+  private fun autoCompleteDataFull(): List<AutoCompleteItem> {
+    return autoCompleteDataRaw.value?.let { (sessionOptional, id, lastWord) ->
+      val session = sessionOptional.orNull()
+      val bufferInfo = session?.bufferSyncer?.bufferInfo(id)
+      session?.networks?.let { networks ->
+        session.bufferSyncer?.bufferInfos()?.let { infos ->
+          if (bufferInfo?.type?.hasFlag(Buffer_Type.ChannelBuffer) == true) {
+            val network = networks[bufferInfo.networkId]
+            network?.ircChannel(
+              bufferInfo.bufferName
+            )?.let { ircChannel ->
+              val users = ircChannel.ircUsers()
+              val buffers = infos
+                .filter {
+                  it.type.toInt() == Buffer_Type.ChannelBuffer.toInt()
+                }.mapNotNull { info ->
+                  networks[info.networkId]?.let { info to it }
+                }.map { (info, network) ->
+                  val channel = network.ircChannel(info.bufferName) ?: IrcChannel.NULL
+                  AutoCompleteItem.ChannelItem(
+                    info = info,
+                    network = network.networkInfo(),
+                    bufferStatus = when (channel) {
+                      IrcChannel.NULL -> BufferStatus.OFFLINE
+                      else            -> BufferStatus.ONLINE
+                    },
+                    description = channel.topic()
+                  )
+                }
+              val nicks = users.map { user ->
+                val userModes = ircChannel.userModes(user)
+                val prefixModes = network.prefixModes()
+
+                val lowestMode = userModes.mapNotNull(prefixModes::indexOf).min()
+                                 ?: prefixModes.size
+
+                AutoCompleteItem.UserItem(
+                  user.nick(),
+                  network.modesToPrefixes(userModes),
+                  lowestMode,
+                  user.realName(),
+                  user.isAway(),
+                  network.support("CASEMAPPING"),
+                  Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let {
+                    "https://www.irccloud.com/avatar-redirect/$it"
+                  }
+                )
+              }
+
+              val ignoredStartingCharacters = charArrayOf(
+                '-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\', '@'
+              )
+
+              (nicks + buffers).filter {
+                it.name.trimStart(*ignoredStartingCharacters)
+                  .startsWith(
+                    lastWord.first.trimStart(*ignoredStartingCharacters),
+                    ignoreCase = true
+                  )
+              }.sorted()
+            }
+          } else null
+        }
+      }
+    } ?: emptyList()
+  }
+
   private fun autoComplete(reverse: Boolean = false) {
     val originalWord = lastWord.value
 
     val previous = autocompletionState
     if (!originalWord.second.isEmpty()) {
-      val autoCompletedWords = autoCompleteData.value?.second.orEmpty()
+      val autoCompletedWords = autoCompleteDataFull()
       if (previous != null && lastWord.value.first == previous.originalWord && lastWord.value.second.start == previous.range.start) {
         val previousIndex = autoCompletedWords.indexOf(previous.completion)
         val autoCompletedWord = if (previousIndex != -1) {
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 76c7c5d82ef01d9969e8878783f1e1e70559bf08..f8a241618cd2e99b8e2eed1209725b1cee27c8d7 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -35,7 +35,7 @@
       android:key="@string/preference_textsize_key"
       android:max="24"
       android:title="@string/preference_textsize_title"
-      robobunny:min="12" />
+      robobunny:min="6" />
 
     <SwitchPreference
       android:defaultValue="false"
@@ -136,4 +136,4 @@
       android:summary="@string/preference_show_notification_summary"
       android:title="@string/preference_show_notification_title" />
   </PreferenceCategory>
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/viewmodel/build.gradle.kts b/viewmodel/build.gradle.kts
index 9f832911d0f4e1e87659e086b2e03d60c7aa5eb2..ebb3b5aa66adcf86078c0cbfae6b83df2d91f24f 100644
--- a/viewmodel/build.gradle.kts
+++ b/viewmodel/build.gradle.kts
@@ -32,6 +32,7 @@ dependencies {
   }
 
   // Utility
+  implementation("io.reactivex.rxjava2", "rxandroid", "2.0.2")
   implementation("io.reactivex.rxjava2", "rxjava", "2.1.9")
   implementation("org.threeten", "threetenbp", "1.3.6", classifier = "no-tzdb")
   implementation("org.jetbrains", "annotations", "16.0.1")
@@ -41,4 +42,4 @@ dependencies {
   implementation(project(":lib")) {
     exclude(group = "org.threeten", module = "threetenbp")
   }
-}
\ No newline at end of file
+}
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 64a57cb96a526926be59961c2c7b6cd3e7f3811c..9b6eb6569be05909d384730d3d14b2558b781083 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
@@ -4,14 +4,21 @@ import android.arch.lifecycle.LiveData
 import android.arch.lifecycle.LiveDataReactiveStreams
 import io.reactivex.*
 import io.reactivex.functions.BiFunction
+import io.reactivex.schedulers.Schedulers
 
 inline fun <T> Observable<T>.toLiveData(
   strategy: BackpressureStrategy = BackpressureStrategy.LATEST
-): LiveData<T> = LiveDataReactiveStreams.fromPublisher(toFlowable(strategy))
+): LiveData<T> = LiveDataReactiveStreams.fromPublisher(
+  subscribeOn(Schedulers.computation()).toFlowable(strategy)
+)
 
-inline fun <T> Maybe<T>.toLiveData(): LiveData<T> = LiveDataReactiveStreams.fromPublisher(toFlowable())
+inline fun <T> Maybe<T>.toLiveData(): LiveData<T> = LiveDataReactiveStreams.fromPublisher(
+  subscribeOn(Schedulers.computation()).toFlowable()
+)
 
-inline fun <T> Flowable<T>.toLiveData(): LiveData<T> = LiveDataReactiveStreams.fromPublisher(this)
+inline fun <T> Flowable<T>.toLiveData(): LiveData<T> = LiveDataReactiveStreams.fromPublisher(
+  subscribeOn(Schedulers.computation())
+)
 
 inline fun <reified A, B> combineLatest(
   a: ObservableSource<A>,
@@ -55,4 +62,4 @@ data class Tuple4<out A, out B, out C, out D>(
   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 d6e90f91c964be7c4557c87a5267f7e2fd9adff3..3a5349e2be82aa90b1ce54335ed06c683c402c3f 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
@@ -214,100 +214,120 @@ class QuasselViewModel : ViewModel() {
 
   val lastWord = BehaviorSubject.create<Observable<Pair<String, IntRange>>>()
 
-  val autoCompleteData: Observable<Pair<String, List<AutoCompleteItem>>> =
+  val rawAutoCompleteData: Observable<Triple<Optional<ISession>, Int, Pair<String, IntRange>>> =
     combineLatest(session, buffer, lastWord).switchMap { (sessionOptional, id, lastWordWrapper) ->
       lastWordWrapper
         .distinctUntilChanged()
-        .switchMap { lastWord ->
-          val session = sessionOptional.orNull()
-          val bufferSyncer = session?.bufferSyncer
-          val bufferInfo = bufferSyncer?.bufferInfo(id)
-          if (bufferSyncer != null) {
-            session.liveNetworks().switchMap { networks ->
-              bufferSyncer.liveBufferInfos().switchMap { infos ->
-                if (bufferInfo?.type?.hasFlag(
-                    Buffer_Type.ChannelBuffer
-                  ) == true) {
-                  val network = networks[bufferInfo.networkId]
-                  val ircChannel = network?.ircChannel(
-                    bufferInfo.bufferName
-                  )
-                  if (ircChannel != null) {
-                    ircChannel.liveIrcUsers().switchMap { users ->
-                      val buffers: List<Observable<AutoCompleteItem.ChannelItem>?> = infos.values
-                        .filter {
-                          it.type.toInt() == Buffer_Type.ChannelBuffer.toInt()
-                        }.mapNotNull { info ->
-                          networks[info.networkId]?.let { info to it }
-                        }.map<Pair<BufferInfo, Network>, Observable<AutoCompleteItem.ChannelItem>?> { (info, network) ->
-                          network.liveIrcChannel(
-                            info.bufferName
-                          ).switchMap { channel ->
-                            channel.liveUpdates().map {
-                              AutoCompleteItem.ChannelItem(
-                                info = info,
-                                network = network.networkInfo(),
-                                bufferStatus = when (it) {
-                                  IrcChannel.NULL -> BufferStatus.OFFLINE
-                                  else            -> BufferStatus.ONLINE
-                                },
-                                description = it.topic()
-                              )
-                            }
-                          }
-                        }
-                      val nicks = users.map<IrcUser, Observable<AutoCompleteItem.UserItem>?> {
-                        it.updates().map { user ->
-                          val userModes = ircChannel.userModes(user)
-                          val prefixModes = network.prefixModes()
-
-                          val lowestMode = userModes.mapNotNull(prefixModes::indexOf).min()
-                                           ?: prefixModes.size
-
-                          AutoCompleteItem.UserItem(
-                            user.nick(),
-                            network.modesToPrefixes(userModes),
-                            lowestMode,
-                            user.realName(),
-                            user.isAway(),
-                            network.support("CASEMAPPING"),
-                            Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let {
-                              "https://www.irccloud.com/avatar-redirect/$it"
-                            }
+        .map { lastWord ->
+          Triple(sessionOptional, id, lastWord)
+        }
+    }
+
+  var time = 0L
+  var previous: Any? = null
+  val autoCompleteData = rawAutoCompleteData
+    .distinctUntilChanged()
+    .debounce(300, TimeUnit.MILLISECONDS)
+    .map {
+      val now = System.currentTimeMillis()
+      val difference = now - time
+      if (difference < 300) {
+        println("Updated too early!: $difference")
+      }
+      time = now
+      if (it == previous) {
+        println("what the fuck")
+      }
+      previous = it
+      it
+    }
+    .switchMap { (sessionOptional, id, lastWord) ->
+      val session = sessionOptional.orNull()
+      val bufferSyncer = session?.bufferSyncer
+      val bufferInfo = bufferSyncer?.bufferInfo(id)
+      if (bufferSyncer != null) {
+        session.liveNetworks().switchMap { networks ->
+          bufferSyncer.liveBufferInfos().switchMap { infos ->
+            if (bufferInfo?.type?.hasFlag(Buffer_Type.ChannelBuffer) == true) {
+              val network = networks[bufferInfo.networkId]
+              val ircChannel = network?.ircChannel(
+                bufferInfo.bufferName
+              )
+              if (ircChannel != null) {
+                ircChannel.liveIrcUsers().switchMap { users ->
+                  val buffers: List<Observable<AutoCompleteItem.ChannelItem>?> = infos.values
+                    .filter {
+                      it.type.toInt() == Buffer_Type.ChannelBuffer.toInt()
+                    }.mapNotNull { info ->
+                      networks[info.networkId]?.let { info to it }
+                    }.map { (info, network) ->
+                      network.liveIrcChannel(
+                        info.bufferName
+                      ).switchMap { channel ->
+                        channel.liveUpdates().map {
+                          AutoCompleteItem.ChannelItem(
+                            info = info,
+                            network = network.networkInfo(),
+                            bufferStatus = when (it) {
+                              IrcChannel.NULL -> BufferStatus.OFFLINE
+                              else            -> BufferStatus.ONLINE
+                            },
+                            description = it.topic()
                           )
                         }
                       }
-
-                      combineLatest<AutoCompleteItem>(nicks + buffers)
-                        .map { list ->
-                          val ignoredStartingCharacters = charArrayOf(
-                            '-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\', '@'
-                          )
-
-                          Pair(
-                            lastWord.first,
-                            list.filter {
-                              it.name.trimStart(*ignoredStartingCharacters)
-                                .startsWith(
-                                  lastWord.first.trimStart(*ignoredStartingCharacters),
-                                  ignoreCase = true
-                                )
-                            }.sorted()
-                          )
+                    }
+                  val nicks = users.map<IrcUser, Observable<AutoCompleteItem.UserItem>?> {
+                    it.updates().map { user ->
+                      val userModes = ircChannel.userModes(user)
+                      val prefixModes = network.prefixModes()
+
+                      val lowestMode = userModes.mapNotNull(prefixModes::indexOf).min()
+                                       ?: prefixModes.size
+
+                      AutoCompleteItem.UserItem(
+                        user.nick(),
+                        network.modesToPrefixes(userModes),
+                        lowestMode,
+                        user.realName(),
+                        user.isAway(),
+                        network.support("CASEMAPPING"),
+                        Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let {
+                          "https://www.irccloud.com/avatar-redirect/$it"
                         }
+                      )
                     }
-                  } else {
-                    Observable.just(Pair(lastWord.first, emptyList()))
                   }
-                } else {
-                  Observable.just(Pair(lastWord.first, emptyList()))
+
+                  combineLatest<AutoCompleteItem>(nicks + buffers)
+                    .map { list ->
+                      val ignoredStartingCharacters = charArrayOf(
+                        '-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\', '@'
+                      )
+
+                      Pair(
+                        lastWord.first,
+                        list.filter {
+                          it.name.trimStart(*ignoredStartingCharacters)
+                            .startsWith(
+                              lastWord.first.trimStart(*ignoredStartingCharacters),
+                              ignoreCase = true
+                            )
+                        }.sorted()
+                      )
+                    }
                 }
+              } else {
+                Observable.just(Pair(lastWord.first, emptyList()))
               }
+            } else {
+              Observable.just(Pair(lastWord.first, emptyList()))
             }
-          } else {
-            Observable.just(Pair(lastWord.first, emptyList()))
           }
         }
+      } else {
+        Observable.just(Pair(lastWord.first, emptyList()))
+      }
     }
 
   val bufferViewConfigs = bufferViewManager.mapSwitchMap { manager ->