diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 50204202560529ea3bf30236e6b6448d782f1c17..7e50d3d1602b8c08f48dd15a88af548b6fb93bb6 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -133,6 +133,7 @@ dependencies {
   }
 
   // Quassel
+  implementation(project(":viewmodel"))
   implementation(project(":lib")) {
     exclude(group = "org.threeten", module = "threetenbp")
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
index 4627d3e556189ec66359032deea8efd3cda42be5..19baffe7bbf551ee7af837b5e76acdc0b4916ce7 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
@@ -34,19 +34,18 @@ import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
 import de.kuschku.quasseldroid_ng.settings.BacklogSettings
 import de.kuschku.quasseldroid_ng.settings.Settings
-import de.kuschku.quasseldroid_ng.ui.chat.input.AutoCompleteAdapter
 import de.kuschku.quasseldroid_ng.ui.chat.input.Editor
 import de.kuschku.quasseldroid_ng.ui.chat.input.MessageHistoryAdapter
 import de.kuschku.quasseldroid_ng.ui.settings.SettingsActivity
 import de.kuschku.quasseldroid_ng.ui.setup.accounts.AccountSelectionActivity
-import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel
 import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
 import de.kuschku.quasseldroid_ng.util.helper.editApply
 import de.kuschku.quasseldroid_ng.util.helper.invoke
-import de.kuschku.quasseldroid_ng.util.helper.let
 import de.kuschku.quasseldroid_ng.util.helper.sharedPreferences
 import de.kuschku.quasseldroid_ng.util.service.ServiceBoundActivity
 import de.kuschku.quasseldroid_ng.util.ui.MaterialContentLoadingProgressBar
+import de.kuschku.quasseldroid_ng.viewmodel.QuasselViewModel
+import de.kuschku.quasseldroid_ng.viewmodel.data.AutoCompleteItem
 
 class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
   @BindView(R.id.drawer_layout)
@@ -125,7 +124,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
       findViewById(R.id.formatting_toolbar),
       { lines ->
         viewModel.session { session ->
-          viewModel.getBuffer().let { bufferId ->
+          viewModel.getBuffer().value?.let { bufferId ->
             session.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo ->
               val output = mutableListOf<IAliasManager.Command>()
               for ((stripped, formatted) in lines) {
@@ -204,8 +203,8 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
   data class AutoCompletionState(
     val originalWord: String,
     val range: IntRange,
-    val lastCompletion: AutoCompleteAdapter.AutoCompleteItem? = null,
-    val completion: AutoCompleteAdapter.AutoCompleteItem
+    val lastCompletion: AutoCompleteItem? = null,
+    val completion: AutoCompleteItem
   )
 
   override fun onSaveInstanceState(outState: Bundle?) {
@@ -298,7 +297,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
     R.id.clear -> {
       handler.post {
         viewModel.sessionManager { manager ->
-          viewModel.getBuffer().let { buffer ->
+          viewModel.getBuffer().value?.let { buffer ->
             manager.backlogStorage.clearMessages(buffer)
             manager.backlogManager?.requestBacklog(
               bufferId = buffer,
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt
index 7c8b69f1c9e36817db540375e36f0d2a066f3d11..466ea7ba1588e273a07266ab167eb928c2940b6e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt
@@ -10,18 +10,16 @@ import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.quassel.BufferInfo
-import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.libquassel.util.hasFlag
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.settings.AppearanceSettings
 import de.kuschku.quasseldroid_ng.settings.Settings
-import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel
 import de.kuschku.quasseldroid_ng.util.helper.visibleIf
 import de.kuschku.quasseldroid_ng.util.helper.zip
 import de.kuschku.quasseldroid_ng.util.irc.format.IrcFormatDeserializer
 import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment
 import de.kuschku.quasseldroid_ng.util.ui.SpanFormatter
+import de.kuschku.quasseldroid_ng.viewmodel.QuasselViewModel
 
 class ToolbarFragment : ServiceBoundFragment() {
   @BindView(R.id.toolbar_title)
@@ -102,10 +100,4 @@ class ToolbarFragment : ServiceBoundFragment() {
     description, appearanceSettings.colorizeMirc
   )
                                                           ?: description
-
-  data class BufferData(
-    val info: BufferInfo? = null,
-    val network: INetwork.NetworkInfo? = null,
-    val description: String? = null
-  )
 }
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt
index f5cbb490b395d697103dbc7e00187f3ebf2ddfda..f4ae35f242b8558d475636803097751807338695 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt
@@ -15,15 +15,21 @@ import android.widget.ImageView
 import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
-import de.kuschku.libquassel.protocol.*
+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.quassel.BufferInfo
-import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.libquassel.util.hasFlag
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.util.helper.getCompatDrawable
 import de.kuschku.quasseldroid_ng.util.helper.styledAttributes
 import de.kuschku.quasseldroid_ng.util.helper.visibleIf
 import de.kuschku.quasseldroid_ng.util.helper.zip
+import de.kuschku.quasseldroid_ng.viewmodel.data.BufferListItem
+import de.kuschku.quasseldroid_ng.viewmodel.data.BufferProps
+import de.kuschku.quasseldroid_ng.viewmodel.data.BufferState
+import de.kuschku.quasseldroid_ng.viewmodel.data.BufferStatus
 
 class BufferListAdapter(
   lifecycleOwner: LifecycleOwner,
@@ -145,33 +151,6 @@ class BufferListAdapter(
 
   override fun getItemViewType(position: Int) = data[position].props.info.type.toInt()
 
-  data class BufferListItem(
-    val props: BufferProps,
-    val state: BufferState
-  )
-
-  data class BufferProps(
-    val info: BufferInfo,
-    val network: INetwork.NetworkInfo,
-    val bufferStatus: BufferStatus,
-    val description: CharSequence,
-    val activity: Message_Types,
-    val highlights: Int = 0,
-    val bufferActivity: Buffer_Activities = Buffer_Activity.of(Buffer_Activity.NoActivity),
-    val hiddenState: HiddenState
-  )
-
-  enum class HiddenState {
-    VISIBLE,
-    HIDDEN_TEMPORARY,
-    HIDDEN_PERMANENT
-  }
-
-  data class BufferState(
-    val networkExpanded: Boolean,
-    val selected: Boolean
-  )
-
   abstract class BufferViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
     abstract fun bind(props: BufferProps, state: BufferState)
 
@@ -522,10 +501,4 @@ class BufferListAdapter(
       }
     }
   }
-
-  enum class BufferStatus {
-    ONLINE,
-    AWAY,
-    OFFLINE
-  }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt
index 2c398209052f36dc82182c8e90267a1a86623035..e491e9592905f06211a7d9f2dbb9cab4184c70a1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt
@@ -13,7 +13,6 @@ 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.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.libquassel.util.hasFlag
 import de.kuschku.libquassel.util.minus
@@ -21,12 +20,13 @@ import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
 import de.kuschku.quasseldroid_ng.settings.AppearanceSettings
 import de.kuschku.quasseldroid_ng.settings.Settings
-import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel
 import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
 import de.kuschku.quasseldroid_ng.util.helper.map
 import de.kuschku.quasseldroid_ng.util.helper.zip
 import de.kuschku.quasseldroid_ng.util.irc.format.IrcFormatDeserializer
 import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment
+import de.kuschku.quasseldroid_ng.viewmodel.QuasselViewModel
+import de.kuschku.quasseldroid_ng.viewmodel.data.BufferHiddenState
 
 class BufferViewConfigFragment : ServiceBoundFragment() {
   private val handlerThread = AndroidHandlerThread("ChatList")
@@ -55,7 +55,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
       val session = viewModel.session.value
       val bufferSyncer = session?.bufferSyncer
       val network = session?.networks?.get(selected?.info?.networkId)
-      val bufferViewConfig = viewModel.getBufferViewConfig().value
+      val bufferViewConfig = viewModel.bufferViewConfig.value
 
       return if (info != null && session != null) {
         when (item?.itemId) {
@@ -88,7 +88,9 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
               .backgroundColorAttr(R.attr.colorBackgroundCard)
               .contentColorAttr(R.attr.colorTextPrimary)
               .onPositive { _, _ ->
-                session.bufferSyncer?.requestRemoveBuffer(selected.info.bufferId)
+                selected.info?.let {
+                  session.bufferSyncer?.requestRemoveBuffer(info.bufferId)
+                }
               }
               .build()
               .show()
@@ -102,7 +104,9 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
                 info.bufferName,
                 false
               ) { _, input ->
-                session.bufferSyncer?.requestRenameBuffer(selected.info.bufferId, input.toString())
+                selected.info?.let {
+                  session.bufferSyncer?.requestRenameBuffer(info.bufferId, input.toString())
+                }
               }
               .positiveText(R.string.label_save)
               .negativeText(R.string.label_cancel)
@@ -176,11 +180,11 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
     chatListSpinner.adapter = adapter
     chatListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
       override fun onNothingSelected(p0: AdapterView<*>?) {
-        viewModel.setBufferViewConfig(null)
+        viewModel.setBufferViewConfigId(null)
       }
 
       override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
-        viewModel.setBufferViewConfig(adapter.getItem(p2))
+        viewModel.setBufferViewConfigId(adapter.getItem(p2)?.bufferViewId())
       }
     }
 
@@ -240,15 +244,15 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
           )
 
           val visibilityActions = when (buffer.hiddenState) {
-            BufferListAdapter.HiddenState.VISIBLE          -> setOf(
+            BufferHiddenState.VISIBLE          -> setOf(
               R.id.action_hide_temp,
               R.id.action_hide_perm
             )
-            BufferListAdapter.HiddenState.HIDDEN_TEMPORARY -> setOf(
+            BufferHiddenState.HIDDEN_TEMPORARY -> setOf(
               R.id.action_unhide,
               R.id.action_hide_perm
             )
-            BufferListAdapter.HiddenState.HIDDEN_PERMANENT -> setOf(
+            BufferHiddenState.HIDDEN_PERMANENT -> setOf(
               R.id.action_unhide,
               R.id.action_hide_temp
             )
@@ -327,11 +331,4 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
     }
     listAdapter.toggleSelection(it)
   }
-
-  data class SelectedItem(
-    val info: BufferInfo? = null,
-    val connectionState: INetwork.ConnectionState = INetwork.ConnectionState.Disconnected,
-    val joined: Boolean = false,
-    val hiddenState: BufferListAdapter.HiddenState = BufferListAdapter.HiddenState.VISIBLE
-  )
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/AutoCompleteAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/AutoCompleteAdapter.kt
index 62778a67e8307673cbf7cda0b99d4b3256bbed85..367406a361199527a1004ca2428839d080ee927b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/AutoCompleteAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/AutoCompleteAdapter.kt
@@ -12,18 +12,17 @@ import android.widget.ImageView
 import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
-import de.kuschku.libquassel.quassel.BufferInfo
-import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 import de.kuschku.quasseldroid_ng.R
-import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferListAdapter
 import de.kuschku.quasseldroid_ng.ui.chat.nicks.NickListAdapter.Companion.VIEWTYPE_AWAY
 import de.kuschku.quasseldroid_ng.util.helper.getCompatDrawable
 import de.kuschku.quasseldroid_ng.util.helper.styledAttributes
 import de.kuschku.quasseldroid_ng.util.helper.visibleIf
+import de.kuschku.quasseldroid_ng.viewmodel.data.AutoCompleteItem
+import de.kuschku.quasseldroid_ng.viewmodel.data.BufferStatus
 
 class AutoCompleteAdapter(
   private val clickListener: ((String) -> Unit)? = null
-) : ListAdapter<AutoCompleteAdapter.AutoCompleteItem, AutoCompleteAdapter.AutoCompleteViewHolder>(
+) : ListAdapter<AutoCompleteItem, AutoCompleteAdapter.AutoCompleteViewHolder>(
   object : DiffUtil.ItemCallback<AutoCompleteItem>() {
     override fun areItemsTheSame(oldItem: AutoCompleteItem, newItem: AutoCompleteItem) =
       oldItem.name == newItem.name
@@ -63,34 +62,6 @@ class AutoCompleteAdapter(
     }
   }
 
-  sealed class AutoCompleteItem(open val name: String) : Comparable<AutoCompleteItem> {
-    override fun compareTo(other: AutoCompleteItem): Int {
-      return when {
-        this is UserItem &&
-        other is ChannelItem -> -1
-        this is ChannelItem &&
-        other is UserItem    -> 1
-        else                 -> this.name.compareTo(other.name)
-      }
-    }
-
-    data class UserItem(
-      val nick: String,
-      val modes: String,
-      val lowestMode: Int,
-      val realname: CharSequence,
-      val away: Boolean,
-      val networkCasemapping: String
-    ) : AutoCompleteItem(nick)
-
-    data class ChannelItem(
-      val info: BufferInfo,
-      val network: INetwork.NetworkInfo,
-      val bufferStatus: BufferListAdapter.BufferStatus,
-      val description: CharSequence
-    ) : AutoCompleteItem(info.bufferName ?: "")
-  }
-
   sealed class AutoCompleteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
     fun bind(data: AutoCompleteItem) = when {
       data is AutoCompleteItem.UserItem && this is NickViewHolder       -> this.bindImpl(data)
@@ -185,8 +156,8 @@ class AutoCompleteAdapter(
 
         status.setImageDrawable(
           when (data.bufferStatus) {
-            BufferListAdapter.BufferStatus.ONLINE -> online
-            else                                  -> offline
+            BufferStatus.ONLINE -> online
+            else                -> offline
           }
         )
       }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/Editor.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/Editor.kt
index d7463e063bceb81a8950d3a800c70b9366e3c808..14a3c5cff9e3672832ff09e1b914c40766e67afc 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/Editor.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/Editor.kt
@@ -18,6 +18,7 @@ import de.kuschku.quasseldroid_ng.ui.chat.ChatActivity
 import de.kuschku.quasseldroid_ng.util.helper.lastWordIndices
 import de.kuschku.quasseldroid_ng.util.helper.lineSequence
 import de.kuschku.quasseldroid_ng.util.helper.retint
+import de.kuschku.quasseldroid_ng.viewmodel.data.AutoCompleteItem
 import io.reactivex.Observable
 import io.reactivex.subjects.BehaviorSubject
 
@@ -25,7 +26,7 @@ class Editor(
   // Contexts
   activity: AppCompatActivity,
   // LiveData
-  private val autoCompleteData: LiveData<Pair<String, List<AutoCompleteAdapter.AutoCompleteItem>>?>,
+  private val autoCompleteData: LiveData<Pair<String, List<AutoCompleteItem>>?>,
   lastWordContainer: MutableLiveData<Observable<Pair<String, IntRange>>>,
   // Views
   val chatline: AppCompatEditText,
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt
index 49a76a1e9f289781e02eec13d300c6f40c5bd742..d27154b6a587e3d8c33deb339f3c1f4f639448f8 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt
@@ -21,10 +21,10 @@ import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
 import de.kuschku.quasseldroid_ng.settings.AppearanceSettings
 import de.kuschku.quasseldroid_ng.settings.BacklogSettings
 import de.kuschku.quasseldroid_ng.settings.Settings
-import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel
 import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
 import de.kuschku.quasseldroid_ng.util.helper.*
 import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment
+import de.kuschku.quasseldroid_ng.viewmodel.QuasselViewModel
 
 class MessageListFragment : ServiceBoundFragment() {
   @BindView(R.id.messages)
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListAdapter.kt
index 2b1a21ee64e6bde3ece12b3b87e386de6a9d6654..9e21c534f8fbca74b33adaeafdbdaeab736199b2 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListAdapter.kt
@@ -11,10 +11,11 @@ import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.util.helper.visibleIf
+import de.kuschku.quasseldroid_ng.viewmodel.data.IrcUserItem
 
 class NickListAdapter(
   private val clickListener: ((String) -> Unit)? = null
-) : ListAdapter<NickListAdapter.IrcUserItem, NickListAdapter.NickViewHolder>(
+) : ListAdapter<IrcUserItem, NickListAdapter.NickViewHolder>(
   object : DiffUtil.ItemCallback<IrcUserItem>() {
     override fun areItemsTheSame(oldItem: IrcUserItem, newItem: IrcUserItem) =
       oldItem.nick == newItem.nick
@@ -42,15 +43,6 @@ class NickListAdapter(
     VIEWTYPE_ACTIVE
   }
 
-  data class IrcUserItem(
-    val nick: String,
-    val modes: String,
-    val lowestMode: Int,
-    val realname: CharSequence,
-    val away: Boolean,
-    val networkCasemapping: String
-  )
-
   class NickViewHolder(
     itemView: View,
     private val clickListener: ((String) -> Unit)? = null
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListFragment.kt
index ba8d29d332b393a6720b2d43774e59f5d56698c1..1abcaf0d8087db52672a3d091a3dad3662ce4252 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListFragment.kt
@@ -15,11 +15,11 @@ import de.kuschku.libquassel.util.irc.IrcCaseMappers
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.settings.AppearanceSettings
 import de.kuschku.quasseldroid_ng.settings.Settings
-import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel
 import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
 import de.kuschku.quasseldroid_ng.util.helper.map
 import de.kuschku.quasseldroid_ng.util.irc.format.IrcFormatDeserializer
 import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment
+import de.kuschku.quasseldroid_ng.viewmodel.QuasselViewModel
 
 class NickListFragment : ServiceBoundFragment() {
   private lateinit var viewModel: QuasselViewModel
diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts
index 8c2b7c1a60beafb58b56e0b60dc5f09af07ecb04..e3cf7c1bacfe6b3185b777e79b30b2718325df33 100644
--- a/lib/build.gradle.kts
+++ b/lib/build.gradle.kts
@@ -19,6 +19,12 @@ dependencies {
   implementation("org.threeten", "threetenbp", "1.3.6")
   implementation("io.reactivex.rxjava2:rxjava:2.1.9")
 
+
+  withVersion("2.15") {
+    implementation("com.google.dagger", "dagger", version)
+    kapt("com.google.dagger", "dagger-compiler", version)
+  }
+
   implementation(project(":invokerannotations"))
   kapt(project(":invokergenerator"))
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt
index f9aad6605da866be1f42ca374e39a7529d638783..23a6d7d5cd551069f83787be391a48b7fb44078f 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt
@@ -2,9 +2,9 @@ package de.kuschku.libquassel.quassel.syncables.interfaces.invokers
 
 import de.kuschku.libquassel.annotations.Syncable
 import de.kuschku.libquassel.quassel.syncables.interfaces.*
+import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN
-import de.kuschku.libquassel.util.compatibility.log
 
 object Invokers {
   private val registry = mutableMapOf<String, Invoker<*>>()
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
index 3723825a162d47fab79c5ec7276ad570f442db6b..88a7df98a87437fccd758bef26b6ab75fdf0482a 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
@@ -1,5 +1,6 @@
 package de.kuschku.libquassel.session
 
+import de.kuschku.libquassel.protocol.ClientData
 import de.kuschku.libquassel.protocol.message.HandshakeMessage
 import de.kuschku.libquassel.protocol.message.SignalProxyMessage
 import de.kuschku.libquassel.protocol.primitive.serializer.HandshakeVariantMapSerializer
@@ -9,8 +10,8 @@ import de.kuschku.libquassel.protocol.primitive.serializer.VariantListSerializer
 import de.kuschku.libquassel.quassel.ProtocolFeature
 import de.kuschku.libquassel.util.compatibility.CompatibilityUtils
 import de.kuschku.libquassel.util.compatibility.HandlerService
+import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.*
-import de.kuschku.libquassel.util.compatibility.log
 import de.kuschku.libquassel.util.hasFlag
 import de.kuschku.libquassel.util.helpers.hexDump
 import de.kuschku.libquassel.util.helpers.write
@@ -24,9 +25,13 @@ import java.lang.Thread.UncaughtExceptionHandler
 import java.net.Socket
 import java.net.SocketException
 import java.nio.ByteBuffer
+import javax.net.ssl.X509TrustManager
 
 class CoreConnection(
-  private val session: Session,
+  private val handler: ProtocolHandler,
+  private val clientData: ClientData,
+  private val features: Features,
+  private val trustManager: X509TrustManager,
   private val address: SocketAddress,
   private val handlerService: HandlerService
 ) : Thread(), Closeable {
@@ -67,13 +72,13 @@ class CoreConnection(
 
     IntSerializer.serialize(
       chainedBuffer,
-      0x42b33f00 or session.clientData.protocolFeatures.toInt(),
-      session.negotiatedFeatures
+      0x42b33f00 or clientData.protocolFeatures.toInt(),
+      features.negotiated
     )
-    for (supportedProtocol in session.clientData.supportedProtocols) {
-      IntSerializer.serialize(chainedBuffer, supportedProtocol.toInt(), session.negotiatedFeatures)
+    for (supportedProtocol in clientData.supportedProtocols) {
+      IntSerializer.serialize(chainedBuffer, supportedProtocol.toInt(), features.negotiated)
     }
-    IntSerializer.serialize(chainedBuffer, 1 shl 31, session.negotiatedFeatures)
+    IntSerializer.serialize(chainedBuffer, 1 shl 31, features.negotiated)
     channel?.write(chainedBuffer)
     channel?.flush()
   }
@@ -82,13 +87,13 @@ class CoreConnection(
     sizeBuffer.clear()
     channel?.read(sizeBuffer)
     sizeBuffer.flip()
-    val protocol = ProtocolInfoSerializer.deserialize(sizeBuffer, session.negotiatedFeatures)
+    val protocol = ProtocolInfoSerializer.deserialize(sizeBuffer, features.negotiated)
 
     log(DEBUG, TAG, "Protocol negotiated $protocol")
 
     // Wrap socket in SSL context if ssl is enabled
     if (protocol.flags.hasFlag(ProtocolFeature.TLS)) {
-      channel = channel?.withSSL(session.trustManager, address)
+      channel = channel?.withSSL(trustManager, address)
     }
 
     // Wrap socket in deflater if compression is enabled
@@ -102,10 +107,10 @@ class CoreConnection(
         // Send client clientData to core
         dispatch(
           HandshakeMessage.ClientInit(
-            clientVersion = session.clientData.identifier,
+            clientVersion = clientData.identifier,
             buildDate = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss")
-              .format(session.clientData.buildDate.atOffset(ZoneOffset.UTC)),
-            clientFeatures = session.clientData.clientFeatures
+              .format(clientData.buildDate.atOffset(ZoneOffset.UTC)),
+            clientFeatures = clientData.clientFeatures
           )
         )
       }
@@ -132,7 +137,7 @@ class CoreConnection(
         handlerService.write(
           MessageRunnable(
             data, HandshakeVariantMapSerializer, chainedBuffer, channel,
-            session.negotiatedFeatures
+            features.negotiated
           )
         )
       } catch (e: Throwable) {
@@ -148,7 +153,7 @@ class CoreConnection(
         handlerService.write(
           MessageRunnable(
             data, VariantListSerializer, chainedBuffer, channel,
-            session.negotiatedFeatures
+            features.negotiated
           )
         )
       } catch (e: Throwable) {
@@ -168,7 +173,7 @@ class CoreConnection(
           break
         sizeBuffer.flip()
 
-        val size = IntSerializer.deserialize(sizeBuffer, session.negotiatedFeatures)
+        val size = IntSerializer.deserialize(sizeBuffer, features.negotiated)
         if (size > 64 * 1024 * 1024)
           throw SocketException("Too large frame received: $size")
         val dataBuffer = ByteBuffer.allocateDirect(size)
@@ -191,11 +196,11 @@ class CoreConnection(
   private fun processSigProxy(dataBuffer: ByteBuffer) {
     try {
       val msg = SignalProxyMessage.deserialize(
-        VariantListSerializer.deserialize(dataBuffer, session.negotiatedFeatures)
+        VariantListSerializer.deserialize(dataBuffer, features.negotiated)
       )
       handlerService.handle {
         try {
-          session.handle(msg)
+          handler.handle(msg)
         } catch (e: Throwable) {
           log(WARN, TAG, "Error encountered while handling sigproxy message", e)
           log(WARN, TAG, msg.toString())
@@ -210,10 +215,10 @@ class CoreConnection(
   private fun processHandshake(dataBuffer: ByteBuffer) {
     try {
       val msg = HandshakeMessage.deserialize(
-        HandshakeVariantMapSerializer.deserialize(dataBuffer, session.negotiatedFeatures)
+        HandshakeVariantMapSerializer.deserialize(dataBuffer, features.negotiated)
       )
       try {
-        session.handle(msg)
+        handler.handle(msg)
       } catch (e: Throwable) {
         log(WARN, TAG, "Error encountered while handling handshake message", e)
         log(WARN, TAG, msg.toString())
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Features.kt b/lib/src/main/java/de/kuschku/libquassel/session/Features.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3c9b095359f040ff8e84c2e2e5d6597655be6bf4
--- /dev/null
+++ b/lib/src/main/java/de/kuschku/libquassel/session/Features.kt
@@ -0,0 +1,12 @@
+package de.kuschku.libquassel.session
+
+import de.kuschku.libquassel.protocol.Quassel_Features
+import de.kuschku.libquassel.util.and
+
+data class Features(
+  var client: Quassel_Features,
+  var core: Quassel_Features
+) {
+  val negotiated: Quassel_Features
+    get() = core and client
+}
\ No newline at end of file
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt b/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt
index 862b13a4d955b8a15b2ef64c5b575a14e85074fe..d594b2a48ee9652fadb5a296bee41030c4b411a7 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt
@@ -11,8 +11,7 @@ import javax.net.ssl.SSLSession
 
 interface ISession : Closeable {
   val state: Observable<ConnectionState>
-  val coreFeatures: Quassel_Features
-  val negotiatedFeatures: Quassel_Features
+  val features: Features
   val sslSession: SSLSession?
 
   val aliasManager: AliasManager?
@@ -35,8 +34,7 @@ interface ISession : Closeable {
   companion object {
     val NULL = object : ISession {
       override val state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED)
-      override val coreFeatures: Quassel_Features = Quassel_Features.of()
-      override val negotiatedFeatures: Quassel_Features = Quassel_Features.of()
+      override val features: Features = Features(Quassel_Features.of(), Quassel_Features.of())
       override val sslSession: SSLSession? = null
 
       override val rpcHandler: RpcHandler? = null
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt
index f48594eb67575206f02b6ae1d950923be6da152e..d253ac080aff943cdb752ea610fb0a3c3c0219af 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt
@@ -2,8 +2,8 @@ package de.kuschku.libquassel.session
 
 import de.kuschku.libquassel.protocol.Quassel_Features
 import de.kuschku.libquassel.protocol.primitive.serializer.Serializer
+import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN
-import de.kuschku.libquassel.util.compatibility.log
 import de.kuschku.libquassel.util.helpers.write
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
 import de.kuschku.libquassel.util.nio.WrappedChannel
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt b/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt
index 8675961766be81e7957fd9d775153ce4e27ec585..b1703df15cc9606119d2f7ae5d195d964842f938 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt
@@ -7,9 +7,9 @@ import de.kuschku.libquassel.quassel.exceptions.ObjectNotFoundException
 import de.kuschku.libquassel.quassel.syncables.RpcHandler
 import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject
 import de.kuschku.libquassel.quassel.syncables.interfaces.invokers.Invokers
+import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN
-import de.kuschku.libquassel.util.compatibility.log
 import org.threeten.bp.Instant
 import java.io.Closeable
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt
index 7fc5c5e613edc090b9fc38fde54a414b6697949b..c3d9191573722c41efe270318eec90a4faeac55b 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt
@@ -5,32 +5,31 @@ import de.kuschku.libquassel.protocol.message.HandshakeMessage
 import de.kuschku.libquassel.protocol.message.SignalProxyMessage
 import de.kuschku.libquassel.quassel.QuasselFeature
 import de.kuschku.libquassel.quassel.syncables.*
-import de.kuschku.libquassel.util.and
 import de.kuschku.libquassel.util.compatibility.HandlerService
+import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
-import de.kuschku.libquassel.util.compatibility.log
 import de.kuschku.libquassel.util.hasFlag
 import io.reactivex.subjects.BehaviorSubject
 import org.threeten.bp.Instant
 import javax.net.ssl.X509TrustManager
 
 class Session(
-  val clientData: ClientData,
-  val trustManager: X509TrustManager,
+  clientData: ClientData,
+  trustManager: X509TrustManager,
   address: SocketAddress,
   handlerService: HandlerService,
   backlogStorage: BacklogStorage,
   private val userData: Pair<String, String>
 ) : ProtocolHandler(), ISession {
-  override var coreFeatures: Quassel_Features = Quassel_Feature.NONE
-  override val negotiatedFeatures
-    get() = coreFeatures and clientData.clientFeatures
+  override val features = Features(clientData.clientFeatures, Quassel_Features.of())
 
   override val sslSession
     get() = coreConnection.sslSession
 
-  private val coreConnection = CoreConnection(this, address, handlerService)
+  private val coreConnection = CoreConnection(
+    this, clientData, features, trustManager, address, handlerService
+  )
   override val state = coreConnection.state
 
   override val aliasManager = AliasManager(this)
@@ -57,7 +56,7 @@ class Session(
   }
 
   override fun handle(f: HandshakeMessage.ClientInitAck): Boolean {
-    coreFeatures = f.coreFeatures ?: Quassel_Feature.NONE
+    features.core = f.coreFeatures ?: Quassel_Feature.NONE
     dispatch(
       HandshakeMessage.ClientLogin(
         user = userData.first,
@@ -97,7 +96,7 @@ class Session(
     synchronize(bufferSyncer, true)
     synchronize(bufferViewManager, true)
     synchronize(coreInfo, true)
-    if (negotiatedFeatures.hasFlag(QuasselFeature.DccFileTransfer))
+    if (features.negotiated.hasFlag(QuasselFeature.DccFileTransfer))
       synchronize(dccConfig, true)
     synchronize(ignoreListManager, true)
     synchronize(ircListHelper, true)
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt
index a657f67f5c6b81f4780c2c0b22687e89a031b015..6507e00e73f1974dc005a5c47cdaa23a36584763 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt
@@ -3,12 +3,11 @@ package de.kuschku.libquassel.session
 import de.kuschku.libquassel.protocol.ClientData
 import de.kuschku.libquassel.protocol.IdentityId
 import de.kuschku.libquassel.protocol.NetworkId
-import de.kuschku.libquassel.protocol.Quassel_Features
 import de.kuschku.libquassel.quassel.syncables.*
 import de.kuschku.libquassel.quassel.syncables.interfaces.invokers.Invokers
 import de.kuschku.libquassel.util.compatibility.HandlerService
 import de.kuschku.libquassel.util.compatibility.LoggingHandler
-import de.kuschku.libquassel.util.compatibility.log
+import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.helpers.or
 import io.reactivex.Observable
 import io.reactivex.functions.BiFunction
@@ -17,10 +16,8 @@ import javax.net.ssl.SSLSession
 import javax.net.ssl.X509TrustManager
 
 class SessionManager(offlineSession: ISession, val backlogStorage: BacklogStorage) : ISession {
-  override val coreFeatures: Quassel_Features
-    get() = session.or(lastSession).coreFeatures
-  override val negotiatedFeatures: Quassel_Features
-    get() = session.or(lastSession).negotiatedFeatures
+  override val features: Features
+    get() = session.or(lastSession).features
   override val sslSession: SSLSession?
     get() = session.or(lastSession).sslSession
   override val aliasManager: AliasManager?
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/LoggingHandler.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/LoggingHandler.kt
index 73aa925a358150bd5c3405d4047207efb2cac77b..efc5ab6e3f1986cafc136477c6e5df4378ab7f5f 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/LoggingHandler.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/LoggingHandler.kt
@@ -32,15 +32,15 @@ abstract class LoggingHandler {
 
   companion object {
     val loggingHandlers: MutableSet<LoggingHandler> = mutableSetOf(JavaLoggingHandler)
-  }
-}
 
-inline fun log(logLevel: LoggingHandler.LogLevel, tag: String, message: String? = null,
-               throwable: Throwable? = null) {
-  LoggingHandler.loggingHandlers
-    .filter { it.isLoggable(logLevel, tag) }
-    .forEach { it.log(logLevel, tag, message, throwable) }
-}
+    inline fun log(logLevel: LoggingHandler.LogLevel, tag: String, message: String? = null,
+                   throwable: Throwable? = null) {
+      LoggingHandler.loggingHandlers
+        .filter { it.isLoggable(logLevel, tag) }
+        .forEach { it.log(logLevel, tag, message, throwable) }
+    }
 
-inline fun log(logLevel: LoggingHandler.LogLevel, tag: String, throwable: Throwable? = null)
-  = log(logLevel, tag, null, throwable)
+    inline fun log(logLevel: LoggingHandler.LogLevel, tag: String, throwable: Throwable? = null) =
+      log(logLevel, tag, null, throwable)
+  }
+}
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/helpers/ArrayHelper.kt b/lib/src/main/java/de/kuschku/libquassel/util/helpers/ArrayHelper.kt
index 279bb3f85ae752a35a5b476d8d585a132a9139ef..8198d4ddf334b5b6a01bb35b0d542a9ded9242b4 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/helpers/ArrayHelper.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/helpers/ArrayHelper.kt
@@ -1,7 +1,7 @@
 package de.kuschku.libquassel.util.helpers
 
+import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN
-import de.kuschku.libquassel.util.compatibility.log
 
 fun ByteArray.hexDump() {
   for (i in 0 until this.size step 33) {
diff --git a/settings.gradle b/settings.gradle
index 89d849405c683e4fcabca331ff54c56bd5d4dfc4..c9875a387ceb33a9fb94b4db61736d80e815851b 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,3 @@
-include ':invokerannotations', ':invokergenerator', ':lib', ':malheur', ':app', ":slidingpanel"
+include ':invokerannotations', ':invokergenerator', ':lib', ':malheur', ':app', ":slidingpanel", ":viewmodel"
 
 rootProject.buildFileName = 'build.gradle.kts'
diff --git a/viewmodel/build.gradle.kts b/viewmodel/build.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..0be2deb0b9626e83365891960030a72173e0ea3f
--- /dev/null
+++ b/viewmodel/build.gradle.kts
@@ -0,0 +1,43 @@
+plugins {
+  id("com.android.library")
+  kotlin("android")
+  kotlin("kapt")
+}
+
+android {
+  compileSdkVersion(27)
+  buildToolsVersion("27.0.3")
+
+  defaultConfig {
+    minSdkVersion(16)
+    targetSdkVersion(27)
+
+    consumerProguardFiles("proguard-rules.pro")
+  }
+}
+
+dependencies {
+  implementation(kotlin("stdlib", "1.2.30"))
+
+  // App Compat
+  withVersion("27.1.0") {
+    implementation("com.android.support", "appcompat-v7", version)
+  }
+
+  // App Arch Lifecycle
+  withVersion("1.1.0") {
+    implementation("android.arch.lifecycle", "extensions", version)
+    implementation("android.arch.lifecycle", "reactivestreams", version)
+    kapt("android.arch.lifecycle", "compiler", version)
+  }
+
+  // Utility
+  implementation("io.reactivex.rxjava2", "rxjava", "2.1.9")
+  implementation("org.threeten", "threetenbp", "1.3.6", classifier = "no-tzdb")
+  implementation("org.jetbrains", "annotations", "15.0")
+
+  // Quassel
+  implementation(project(":lib")) {
+    exclude(group = "org.threeten", module = "threetenbp")
+  }
+}
\ No newline at end of file
diff --git a/viewmodel/proguard-rules.pro b/viewmodel/proguard-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/viewmodel/src/main/AndroidManifest.xml b/viewmodel/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..834be47102421f39909545a27175413cecd4fd87
--- /dev/null
+++ b/viewmodel/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="de.kuschku.quasseldroid_ng.viewmodel"></manifest>
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt
similarity index 100%
rename from app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt
rename to viewmodel/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataZipHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataZipHelper.kt
similarity index 97%
rename from app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataZipHelper.kt
rename to viewmodel/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataZipHelper.kt
index 47836fb3064218d4a88728fee4053b4b4112ffcf..7e650dece2ebda3db2de2b926146b3b8e230dc36 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataZipHelper.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataZipHelper.kt
@@ -93,7 +93,8 @@ fun <A, B, C> zipLiveData(a: LiveData<A>, b: LiveData<B>,
  * @see zipLiveData
  * @author Mitchell Skaggs
  */
-fun <A, B> LiveData<A>.zip(b: LiveData<B>): LiveData<Pair<A, B>> = zipLiveData(this, b)
+fun <A, B> LiveData<A>.zip(b: LiveData<B>): LiveData<Pair<A, B>> =
+  zipLiveData(this, b)
 
 /**
  * This is merely an extension function for [zipLiveData].
@@ -102,4 +103,5 @@ fun <A, B> LiveData<A>.zip(b: LiveData<B>): LiveData<Pair<A, B>> = zipLiveData(t
  * @author Mitchell Skaggs
  */
 fun <A, B, C> LiveData<A>.zip(b: LiveData<B>,
-                              c: LiveData<C>): LiveData<Triple<A, B, C>> = zipLiveData(this, b, c)
\ No newline at end of file
+                              c: LiveData<C>): LiveData<Triple<A, B, C>> =
+  zipLiveData(this, b, c)
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ObservableHelper.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ObservableHelper.kt
similarity index 100%
rename from app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ObservableHelper.kt
rename to viewmodel/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ObservableHelper.kt
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/QuasselViewModel.kt
similarity index 77%
rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt
rename to viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/QuasselViewModel.kt
index fa61f0f236187782d655769fd66b4d27c7cec2ed..7aca16bb7c77d1341b423441ac71113525a7f775 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/QuasselViewModel.kt
@@ -1,4 +1,4 @@
-package de.kuschku.quasseldroid_ng.ui.viewmodel
+package de.kuschku.quasseldroid_ng.viewmodel
 
 import android.arch.lifecycle.LiveData
 import android.arch.lifecycle.MutableLiveData
@@ -13,15 +13,10 @@ import de.kuschku.libquassel.quassel.syncables.IrcUser
 import de.kuschku.libquassel.quassel.syncables.Network
 import de.kuschku.libquassel.session.Backend
 import de.kuschku.libquassel.session.ISession
-import de.kuschku.libquassel.session.SessionManager
 import de.kuschku.libquassel.util.and
 import de.kuschku.libquassel.util.hasFlag
-import de.kuschku.quasseldroid_ng.ui.chat.ToolbarFragment
-import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferListAdapter
-import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferViewConfigFragment
-import de.kuschku.quasseldroid_ng.ui.chat.input.AutoCompleteAdapter
-import de.kuschku.quasseldroid_ng.ui.chat.nicks.NickListAdapter
 import de.kuschku.quasseldroid_ng.util.helper.*
+import de.kuschku.quasseldroid_ng.viewmodel.data.*
 import io.reactivex.Observable
 import java.util.concurrent.TimeUnit
 
@@ -37,10 +32,10 @@ class QuasselViewModel : ViewModel() {
     this.buffer.value = buffer
   }
 
-  private val bufferViewConfig = MutableLiveData<BufferViewConfig?>()
-  fun getBufferViewConfig(): LiveData<BufferViewConfig?> = bufferViewConfig
-  fun setBufferViewConfig(bufferViewConfig: BufferViewConfig?) {
-    this.bufferViewConfig.value = bufferViewConfig
+  private val bufferViewConfigId = MutableLiveData<Int?>()
+  fun getBufferViewConfigId(): LiveData<Int?> = bufferViewConfigId
+  fun setBufferViewConfigId(bufferViewConfig: Int?) {
+    this.bufferViewConfigId.value = bufferViewConfig
   }
 
   val MAX_RECENT_MESSAGES = 20
@@ -61,6 +56,12 @@ class QuasselViewModel : ViewModel() {
 
   private val bufferViewManager = session.map(ISession::bufferViewManager)
 
+  val bufferViewConfig = bufferViewManager.switchMap { manager ->
+    bufferViewConfigId.map { id ->
+      manager.bufferViewConfig(id)
+    }
+  }
+
   private var lastMarkerLine = -1
   /**
    * An observable of the changes of the markerline, as pairs of `(old, new)`
@@ -87,10 +88,9 @@ class QuasselViewModel : ViewModel() {
     }
   }
 
-  val lag: LiveData<Long?> = sessionManager.switchMapRx { it.session.switchMap { it.lag } }
+  val lag: LiveData<Long?> = session.switchMapRx(ISession::lag)
 
-  val isSecure: LiveData<Boolean?> = sessionManager.switchMapRx(SessionManager::session)
-    .switchMapRx { session ->
+  val isSecure: LiveData<Boolean?> = session.switchMapRx { session ->
       session.state.map { _ ->
         session.sslSession != null
       }
@@ -103,13 +103,13 @@ class QuasselViewModel : ViewModel() {
         val info = bufferSyncer.bufferInfo(id)
         val network = session.networks[info?.networkId]
         if (info == null || network == null) {
-          Observable.just(ToolbarFragment.BufferData())
+          Observable.just(BufferData())
         } else {
           when (info.type.toInt()) {
             BufferInfo.Type.QueryBuffer.toInt()   -> {
               network.liveIrcUser(info.bufferName).switchMap { user ->
                 user.liveRealName().map { realName ->
-                  ToolbarFragment.BufferData(
+                  BufferData(
                     info = info,
                     network = network.networkInfo(),
                     description = realName
@@ -122,7 +122,7 @@ class QuasselViewModel : ViewModel() {
                 info.bufferName
               ).switchMap { channel ->
                 channel.liveTopic().map { topic ->
-                  ToolbarFragment.BufferData(
+                  BufferData(
                     info = info,
                     network = network.networkInfo(),
                     description = topic
@@ -132,14 +132,14 @@ class QuasselViewModel : ViewModel() {
             }
             BufferInfo.Type.StatusBuffer.toInt()  -> {
               network.liveConnectionState.map {
-                ToolbarFragment.BufferData(
+                BufferData(
                   info = info,
                   network = network.networkInfo()
                 )
               }
             }
             else                                  -> Observable.just(
-              ToolbarFragment.BufferData(
+              BufferData(
                 description = "type is unknown: ${info.type.toInt()}"
               )
             )
@@ -147,11 +147,11 @@ class QuasselViewModel : ViewModel() {
         }
       }
     } else {
-      Observable.just(ToolbarFragment.BufferData())
+      Observable.just(BufferData())
     }
   }
 
-  val nickData: LiveData<List<NickListAdapter.IrcUserItem>?> = session.zip(
+  val nickData: LiveData<List<IrcUserItem>?> = session.zip(
     buffer
   ).switchMapRx { (session, buffer) ->
     val bufferSyncer = session?.bufferSyncer
@@ -161,8 +161,8 @@ class QuasselViewModel : ViewModel() {
       val ircChannel = network?.ircChannel(bufferInfo.bufferName)
       if (ircChannel != null) {
         ircChannel.liveIrcUsers().switchMap { users ->
-          combineLatest<NickListAdapter.IrcUserItem>(
-            users.map<IrcUser, Observable<NickListAdapter.IrcUserItem>?> { user ->
+          combineLatest<IrcUserItem>(
+            users.map<IrcUser, Observable<IrcUserItem>?> { user ->
               user.liveNick().switchMap { nick ->
                 user.liveRealName().switchMap { realName ->
                   user.liveIsAway().map { away ->
@@ -173,7 +173,7 @@ class QuasselViewModel : ViewModel() {
                       prefixModes.indexOf(it)
                     }.min() ?: prefixModes.size
 
-                    NickListAdapter.IrcUserItem(
+                    IrcUserItem(
                       nick,
                       network.modesToPrefixes(userModes),
                       lowestMode,
@@ -196,7 +196,7 @@ class QuasselViewModel : ViewModel() {
 
   val lastWord = MutableLiveData<Observable<Pair<String, IntRange>>>()
 
-  val autoCompleteData: LiveData<Pair<String, List<AutoCompleteAdapter.AutoCompleteItem>>?> = session.zip(
+  val autoCompleteData: LiveData<Pair<String, List<AutoCompleteItem>>?> = session.zip(
     buffer, lastWord
   ).switchMapRx { (session, id, lastWordWrapper) ->
     lastWordWrapper
@@ -216,29 +216,29 @@ class QuasselViewModel : ViewModel() {
               )
               if (ircChannel != null) {
                 ircChannel.liveIrcUsers().switchMap { users ->
-                  val buffers: List<Observable<AutoCompleteAdapter.AutoCompleteItem.ChannelItem>?> = infos.values
+                  val buffers: List<Observable<AutoCompleteItem.ChannelItem>?> = infos.values
                     .filter {
                       it.type.toInt() == Buffer_Type.ChannelBuffer.toInt()
                     }.mapNotNull { info ->
                       session.networks[info.networkId]?.let { info to it }
-                    }.map<Pair<BufferInfo, Network>, Observable<AutoCompleteAdapter.AutoCompleteItem.ChannelItem>?> { (info, network) ->
+                    }.map<Pair<BufferInfo, Network>, Observable<AutoCompleteItem.ChannelItem>?> { (info, network) ->
                       network.liveIrcChannel(
                         info.bufferName
                       ).switchMap { channel ->
                         channel.liveTopic().map { topic ->
-                          AutoCompleteAdapter.AutoCompleteItem.ChannelItem(
+                          AutoCompleteItem.ChannelItem(
                             info = info,
                             network = network.networkInfo(),
                             bufferStatus = when (channel) {
-                              IrcChannel.NULL -> BufferListAdapter.BufferStatus.OFFLINE
-                              else            -> BufferListAdapter.BufferStatus.ONLINE
+                              IrcChannel.NULL -> BufferStatus.OFFLINE
+                              else            -> BufferStatus.ONLINE
                             },
                             description = topic
                           )
                         }
                       }
                     }
-                  val nicks = users.map<IrcUser, Observable<AutoCompleteAdapter.AutoCompleteItem.UserItem>?> { user ->
+                  val nicks = users.map<IrcUser, Observable<AutoCompleteItem.UserItem>?> { user ->
                     user.liveNick().switchMap { nick ->
                       user.liveRealName().switchMap { realName ->
                         user.liveIsAway().map { away ->
@@ -253,7 +253,7 @@ class QuasselViewModel : ViewModel() {
                             )
                           }.min() ?: prefixModes.size
 
-                          AutoCompleteAdapter.AutoCompleteItem.UserItem(
+                          AutoCompleteItem.UserItem(
                             nick,
                             network.modesToPrefixes(
                               userModes
@@ -270,7 +270,7 @@ class QuasselViewModel : ViewModel() {
                     }
                   }
 
-                  combineLatest<AutoCompleteAdapter.AutoCompleteItem>(nicks + buffers)
+                  combineLatest<AutoCompleteItem>(nicks + buffers)
                     .map { list ->
                       val ignoredStartingCharacters = charArrayOf(
                         '-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\'
@@ -324,11 +324,11 @@ class QuasselViewModel : ViewModel() {
     if (bufferSyncer != null && bufferViewConfig != null) {
       val hiddenState = when {
         bufferViewConfig.removedBuffers().contains(buffer)            ->
-          BufferListAdapter.HiddenState.HIDDEN_PERMANENT
+          BufferHiddenState.HIDDEN_PERMANENT
         bufferViewConfig.temporarilyRemovedBuffers().contains(buffer) ->
-          BufferListAdapter.HiddenState.HIDDEN_TEMPORARY
+          BufferHiddenState.HIDDEN_TEMPORARY
         else                                                          ->
-          BufferListAdapter.HiddenState.VISIBLE
+          BufferHiddenState.VISIBLE
       }
 
       val info = bufferSyncer.bufferInfo(buffer)
@@ -337,7 +337,7 @@ class QuasselViewModel : ViewModel() {
         when (info.type.enabledValues().firstOrNull()) {
           Buffer_Type.StatusBuffer  -> {
             network?.liveConnectionState?.map {
-              BufferViewConfigFragment.SelectedItem(
+              SelectedBufferItem(
                 info,
                 connectionState = it,
                 hiddenState = hiddenState
@@ -346,7 +346,7 @@ class QuasselViewModel : ViewModel() {
           }
           Buffer_Type.ChannelBuffer -> {
             network?.liveIrcChannel(info.bufferName)?.map {
-              BufferViewConfigFragment.SelectedItem(
+              SelectedBufferItem(
                 info,
                 joined = it != IrcChannel.NULL,
                 hiddenState = hiddenState
@@ -354,17 +354,17 @@ class QuasselViewModel : ViewModel() {
             }
           }
           else                      ->
-            Observable.just(BufferViewConfigFragment.SelectedItem(info, hiddenState = hiddenState))
+            Observable.just(SelectedBufferItem(info, hiddenState = hiddenState))
         }
       } else {
-        Observable.just(BufferViewConfigFragment.SelectedItem(info, hiddenState = hiddenState))
+        Observable.just(SelectedBufferItem(info, hiddenState = hiddenState))
       }
     } else {
-      Observable.just(BufferViewConfigFragment.SelectedItem())
+      Observable.just(SelectedBufferItem())
     }
   }
 
-  val bufferList: LiveData<Pair<BufferViewConfig?, List<BufferListAdapter.BufferProps>>?> = session.zip(
+  val bufferList: LiveData<Pair<BufferViewConfig?, List<BufferProps>>?> = session.zip(
     bufferViewConfig, showHidden
   ).switchMapRx { (session, config, showHiddenRaw) ->
     val bufferSyncer = session?.bufferSyncer
@@ -378,7 +378,7 @@ class QuasselViewModel : ViewModel() {
             config.live_removedBuffers
           )
         ).switchMap { (ids, temp, perm) ->
-          fun transformIds(ids: Collection<BufferId>, state: BufferListAdapter.HiddenState) =
+          fun transformIds(ids: Collection<BufferId>, state: BufferHiddenState) =
             ids.mapNotNull { id ->
               bufferSyncer.bufferInfo(id)
             }.filter {
@@ -393,7 +393,7 @@ class QuasselViewModel : ViewModel() {
               } else {
                 it to network
               }
-            }.map<Pair<BufferInfo, Network>, Observable<BufferListAdapter.BufferProps>?> { (info, network) ->
+            }.map<Pair<BufferInfo, Network>, Observable<BufferProps>?> { (info, network) ->
               bufferSyncer.liveActivity(info.bufferId).switchMap { activity ->
                 bufferSyncer.liveHighlightCount(info.bufferId).map { highlights ->
                   activity to highlights
@@ -404,13 +404,13 @@ class QuasselViewModel : ViewModel() {
                     network.liveIrcUser(info.bufferName).switchMap { user ->
                       user.liveIsAway().switchMap { away ->
                         user.liveRealName().map { realName ->
-                          BufferListAdapter.BufferProps(
+                          BufferProps(
                             info = info,
                             network = network.networkInfo(),
                             bufferStatus = when {
-                              user == IrcUser.NULL -> BufferListAdapter.BufferStatus.OFFLINE
-                              away                 -> BufferListAdapter.BufferStatus.AWAY
-                              else                 -> BufferListAdapter.BufferStatus.ONLINE
+                              user == IrcUser.NULL -> BufferStatus.OFFLINE
+                              away                 -> BufferStatus.AWAY
+                              else                 -> BufferStatus.ONLINE
                             },
                             description = realName,
                             activity = activity,
@@ -426,12 +426,12 @@ class QuasselViewModel : ViewModel() {
                       info.bufferName
                     ).switchMap { channel ->
                       channel.liveTopic().map { topic ->
-                        BufferListAdapter.BufferProps(
+                        BufferProps(
                           info = info,
                           network = network.networkInfo(),
                           bufferStatus = when (channel) {
-                            IrcChannel.NULL -> BufferListAdapter.BufferStatus.OFFLINE
-                            else            -> BufferListAdapter.BufferStatus.ONLINE
+                            IrcChannel.NULL -> BufferStatus.OFFLINE
+                            else            -> BufferStatus.ONLINE
                           },
                           description = topic,
                           activity = activity,
@@ -443,10 +443,10 @@ class QuasselViewModel : ViewModel() {
                   }
                   BufferInfo.Type.StatusBuffer.toInt()  -> {
                     network.liveConnectionState.map {
-                      BufferListAdapter.BufferProps(
+                      BufferProps(
                         info = info,
                         network = network.networkInfo(),
-                        bufferStatus = BufferListAdapter.BufferStatus.OFFLINE,
+                        bufferStatus = BufferStatus.OFFLINE,
                         description = "",
                         activity = activity,
                         highlights = highlights,
@@ -455,10 +455,10 @@ class QuasselViewModel : ViewModel() {
                     }
                   }
                   else                                  -> Observable.just(
-                    BufferListAdapter.BufferProps(
+                    BufferProps(
                       info = info,
                       network = network.networkInfo(),
-                      bufferStatus = BufferListAdapter.BufferStatus.OFFLINE,
+                      bufferStatus = BufferStatus.OFFLINE,
                       description = "",
                       activity = activity,
                       highlights = highlights,
@@ -471,19 +471,19 @@ class QuasselViewModel : ViewModel() {
 
           bufferSyncer.liveBufferInfos().switchMap {
             val buffers = if (showHidden) {
-              transformIds(ids, BufferListAdapter.HiddenState.VISIBLE) +
-              transformIds(temp, BufferListAdapter.HiddenState.HIDDEN_TEMPORARY) +
-              transformIds(perm, BufferListAdapter.HiddenState.HIDDEN_PERMANENT)
+              transformIds(ids, BufferHiddenState.VISIBLE) +
+              transformIds(temp, BufferHiddenState.HIDDEN_TEMPORARY) +
+              transformIds(perm, BufferHiddenState.HIDDEN_PERMANENT)
             } else {
-              transformIds(ids, BufferListAdapter.HiddenState.VISIBLE)
+              transformIds(ids, BufferHiddenState.VISIBLE)
             }
 
-            combineLatest<BufferListAdapter.BufferProps>(buffers).map { list ->
-              Pair<BufferViewConfig?, List<BufferListAdapter.BufferProps>>(
+            combineLatest<BufferProps>(buffers).map { list ->
+              Pair<BufferViewConfig?, List<BufferProps>>(
                 config,
                 list.filter {
                   (!config.hideInactiveBuffers()) ||
-                  it.bufferStatus != BufferListAdapter.BufferStatus.OFFLINE ||
+                  it.bufferStatus != BufferStatus.OFFLINE ||
                   it.info.type.hasFlag(Buffer_Type.StatusBuffer)
                 })
             }
@@ -492,7 +492,7 @@ class QuasselViewModel : ViewModel() {
       }
     } else {
       Observable.just(
-        Pair<BufferViewConfig?, List<BufferListAdapter.BufferProps>>(null, emptyList())
+        Pair<BufferViewConfig?, List<BufferProps>>(null, emptyList())
       )
     }
   }
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/AutoCompleteItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/AutoCompleteItem.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0a27fcbed29ef738a7ba498f686022d21358cbb7
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/AutoCompleteItem.kt
@@ -0,0 +1,32 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
+
+sealed class AutoCompleteItem(open val name: String) : Comparable<AutoCompleteItem> {
+  override fun compareTo(other: AutoCompleteItem): Int {
+    return when {
+      this is UserItem &&
+      other is ChannelItem -> -1
+      this is ChannelItem &&
+      other is UserItem    -> 1
+      else                 -> this.name.compareTo(other.name)
+    }
+  }
+
+  data class UserItem(
+    val nick: String,
+    val modes: String,
+    val lowestMode: Int,
+    val realname: CharSequence,
+    val away: Boolean,
+    val networkCasemapping: String
+  ) : AutoCompleteItem(nick)
+
+  data class ChannelItem(
+    val info: BufferInfo,
+    val network: INetwork.NetworkInfo,
+    val bufferStatus: BufferStatus,
+    val description: CharSequence
+  ) : AutoCompleteItem(info.bufferName ?: "")
+}
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferData.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..915a98732032605c7c776af0cb4dd96aa0de0b13
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferData.kt
@@ -0,0 +1,10 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
+
+data class BufferData(
+  val info: BufferInfo? = null,
+  val network: INetwork.NetworkInfo? = null,
+  val description: String? = null
+)
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferHiddenState.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferHiddenState.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6198395301eff9ded6e3bd39017989a1f2ea071a
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferHiddenState.kt
@@ -0,0 +1,8 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+enum class BufferHiddenState {
+  VISIBLE,
+  HIDDEN_TEMPORARY,
+  HIDDEN_PERMANENT
+}
+
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferListItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferListItem.kt
new file mode 100644
index 0000000000000000000000000000000000000000..27243657bee95a10bd97d360f096693840406c2f
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferListItem.kt
@@ -0,0 +1,6 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+data class BufferListItem(
+  val props: BufferProps,
+  val state: BufferState
+)
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferProps.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferProps.kt
new file mode 100644
index 0000000000000000000000000000000000000000..53757d484112bb0a897e48bceaa3be2cc3de20f1
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferProps.kt
@@ -0,0 +1,19 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+import de.kuschku.libquassel.protocol.Buffer_Activities
+import de.kuschku.libquassel.protocol.Message_Types
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
+
+data class BufferProps(
+  val info: BufferInfo,
+  val network: INetwork.NetworkInfo,
+  val bufferStatus: BufferStatus,
+  val description: CharSequence,
+  val activity: Message_Types,
+  val highlights: Int = 0,
+  val bufferActivity: Buffer_Activities = BufferInfo.Activity.of(
+    BufferInfo.Activity.NoActivity
+  ),
+  val hiddenState: BufferHiddenState
+)
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferState.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferState.kt
new file mode 100644
index 0000000000000000000000000000000000000000..361a42da602774771c155d93beb775b0c01701e6
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferState.kt
@@ -0,0 +1,6 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+data class BufferState(
+  val networkExpanded: Boolean,
+  val selected: Boolean
+)
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferStatus.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferStatus.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d182f0f9befa71f952a17cb9f7c52e3d80a7b382
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/BufferStatus.kt
@@ -0,0 +1,7 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+enum class BufferStatus {
+  ONLINE,
+  AWAY,
+  OFFLINE
+}
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/IrcUserItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/IrcUserItem.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ce9af2f2b6994e68ec3f6fa17a9ee830e4aa71e1
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/IrcUserItem.kt
@@ -0,0 +1,10 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+data class IrcUserItem(
+  val nick: String,
+  val modes: String,
+  val lowestMode: Int,
+  val realname: CharSequence,
+  val away: Boolean,
+  val networkCasemapping: String
+)
\ No newline at end of file
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/SelectedBufferItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/SelectedBufferItem.kt
new file mode 100644
index 0000000000000000000000000000000000000000..617f50e0ccdfc5a6c0b09825e664655d1ba5798b
--- /dev/null
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid_ng/viewmodel/data/SelectedBufferItem.kt
@@ -0,0 +1,11 @@
+package de.kuschku.quasseldroid_ng.viewmodel.data
+
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
+
+data class SelectedBufferItem(
+  val info: BufferInfo? = null,
+  val connectionState: INetwork.ConnectionState = INetwork.ConnectionState.Disconnected,
+  val joined: Boolean = false,
+  val hiddenState: BufferHiddenState = BufferHiddenState.VISIBLE
+)
\ No newline at end of file