From 6998e4933b78fbbacb1d0d3d69817b521891634a Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sat, 31 Mar 2018 11:39:49 +0200
Subject: [PATCH] Show avatars in autocomplete and nicklist

---
 .../quasseldroid/ui/chat/ChatActivity.kt      | 10 ++-
 .../quasseldroid/ui/chat/ToolbarFragment.kt   |  2 +-
 .../ui/chat/buffers/BufferListAdapter.kt      |  2 +-
 .../chat/buffers/BufferViewConfigFragment.kt  |  4 +-
 .../ui/chat/input/AutoCompleteAdapter.kt      | 45 +++++++-----
 .../quasseldroid/ui/chat/input/Editor.kt      | 67 ++++++++++++++++-
 .../ui/chat/messages/MessageAdapter.kt        |  2 +-
 .../chat/messages/QuasselMessageRenderer.kt   |  6 +-
 .../ui/chat/nicks/NickListAdapter.kt          | 34 ++++++---
 .../ui/chat/nicks/NickListFragment.kt         | 70 +++++++++++++++++-
 .../main/res/layout/fragment_nick_list.xml    |  1 +
 .../res/layout/widget_chatmessage_plain.xml   |  6 +-
 app/src/main/res/layout/widget_nick.xml       | 72 +++++++------------
 app/src/main/res/layout/widget_nick_away.xml  | 72 +++++++------------
 .../de/kuschku/libquassel/protocol/Message.kt | 10 +--
 .../de/kuschku/libquassel/protocol/QTypes.kt  |  4 +-
 .../message/ClientInitAckSerializer.kt        |  2 +-
 .../protocol/message/ClientInitSerializer.kt  |  2 +-
 .../kuschku/libquassel/quassel/BufferInfo.kt  |  8 +--
 .../libquassel/quassel/LegacyFeature.kt       |  7 +-
 .../libquassel/quassel/ProtocolFeature.kt     |  7 +-
 .../quassel/syncables/interfaces/INetwork.kt  |  7 +-
 .../libquassel/session/CoreConnection.kt      |  2 +-
 .../de/kuschku/libquassel/util}/CRCUtils.kt   |  2 +-
 .../kuschku/libquassel/util}/IrcUserUtils.kt  |  2 +-
 .../libquassel/util/{ => flag}/Flag.kt        | 51 ++++++++-----
 .../libquassel/util/{ => flag}/LongFlag.kt    | 51 ++++++++-----
 .../libquassel/util/{ => flag}/ShortFlag.kt   | 51 ++++++++-----
 .../viewmodel/QuasselViewModel.kt             | 14 ++--
 .../viewmodel/data/AutoCompleteItem.kt        |  6 +-
 .../viewmodel/data/IrcUserItem.kt             |  7 +-
 31 files changed, 408 insertions(+), 218 deletions(-)
 rename {app/src/main/java/de/kuschku/quasseldroid/util/quassel => lib/src/main/java/de/kuschku/libquassel/util}/CRCUtils.kt (94%)
 rename {app/src/main/java/de/kuschku/quasseldroid/util/quassel => lib/src/main/java/de/kuschku/libquassel/util}/IrcUserUtils.kt (97%)
 rename lib/src/main/java/de/kuschku/libquassel/util/{ => flag}/Flag.kt (69%)
 rename lib/src/main/java/de/kuschku/libquassel/util/{ => flag}/LongFlag.kt (69%)
 rename lib/src/main/java/de/kuschku/libquassel/util/{ => flag}/ShortFlag.kt (72%)

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 ceb44aee9..8552ed8d6 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
@@ -26,8 +26,8 @@ import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.protocol.message.HandshakeMessage
 import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
 import de.kuschku.libquassel.session.ConnectionState
-import de.kuschku.libquassel.util.and
-import de.kuschku.libquassel.util.or
+import de.kuschku.libquassel.util.flag.and
+import de.kuschku.libquassel.util.flag.or
 import de.kuschku.quasseldroid.Keys
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.AccountDatabase
@@ -41,6 +41,7 @@ import de.kuschku.quasseldroid.util.helper.editCommit
 import de.kuschku.quasseldroid.util.helper.invoke
 import de.kuschku.quasseldroid.util.helper.retint
 import de.kuschku.quasseldroid.util.helper.toLiveData
+import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
 import de.kuschku.quasseldroid.util.service.ServiceBoundActivity
 import de.kuschku.quasseldroid.util.ui.MaterialContentLoadingProgressBar
 import de.kuschku.quasseldroid.viewmodel.data.AutoCompleteItem
@@ -76,6 +77,9 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
   @Inject
   lateinit var messageSettings: MessageSettings
 
+  @Inject
+  lateinit var ircFormatDeserializer: IrcFormatDeserializer
+
   private lateinit var editor: Editor
 
   private val panelSlideListener: SlidingUpPanelLayout.PanelSlideListener = object :
@@ -117,8 +121,10 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
         findViewById(R.id.autocomplete_list_expanded)
       ),
       findViewById(R.id.formatting_toolbar),
+      ircFormatDeserializer,
       appearanceSettings,
       autoCompleteSettings,
+      messageSettings,
       { lines ->
         viewModel.session { sessionOptional ->
           val session = sessionOptional.orNull()
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt
index 6c205aea3..ca7cd350e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt
@@ -11,7 +11,7 @@ import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.Buffer_Type
 import de.kuschku.libquassel.quassel.BufferInfo
-import de.kuschku.libquassel.util.hasFlag
+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
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt
index cd6b7773e..271f9c5cf 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt
@@ -18,7 +18,7 @@ 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.util.hasFlag
+import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.util.helper.*
 import de.kuschku.quasseldroid.viewmodel.data.BufferListItem
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
index 857ca41fb..a568631db 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
@@ -13,9 +13,9 @@ 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.syncables.interfaces.INetwork
-import de.kuschku.libquassel.util.hasFlag
+import de.kuschku.libquassel.util.flag.hasFlag
+import de.kuschku.libquassel.util.flag.minus
 import de.kuschku.libquassel.util.helpers.value
-import de.kuschku.libquassel.util.minus
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.QuasselDatabase
 import de.kuschku.quasseldroid.settings.AppearanceSettings
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt
index 0f1903e00..0b030e719 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt
@@ -11,16 +11,21 @@ import android.widget.ImageView
 import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
+import com.bumptech.glide.request.RequestOptions
+import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.nicks.NickListAdapter.Companion.VIEWTYPE_AWAY
 import de.kuschku.quasseldroid.util.helper.getDrawableCompat
 import de.kuschku.quasseldroid.util.helper.styledAttributes
 import de.kuschku.quasseldroid.util.helper.tint
 import de.kuschku.quasseldroid.util.helper.visibleIf
+import de.kuschku.quasseldroid.util.ui.SpanFormatter
 import de.kuschku.quasseldroid.viewmodel.data.AutoCompleteItem
 import de.kuschku.quasseldroid.viewmodel.data.BufferStatus
 
 class AutoCompleteAdapter(
+  private val messageSettings: MessageSettings,
   private val clickListener: ((String) -> Unit)? = null
 ) : ListAdapter<AutoCompleteItem, AutoCompleteAdapter.AutoCompleteViewHolder>(
   object : DiffUtil.ItemCallback<AutoCompleteItem>() {
@@ -37,15 +42,21 @@ class AutoCompleteAdapter(
         .inflate(R.layout.widget_buffer, parent, false),
       clickListener = clickListener
     )
-    VIEWTYPE_NICK_ACTIVE, VIEWTYPE_NICK_AWAY -> AutoCompleteViewHolder.NickViewHolder(
-      LayoutInflater.from(parent.context).inflate(
-        when (viewType) {
-          VIEWTYPE_AWAY -> R.layout.widget_nick_away
-          else          -> R.layout.widget_nick
-        }, parent, false
-      ),
-      clickListener = clickListener
-    )
+    VIEWTYPE_NICK_ACTIVE, VIEWTYPE_NICK_AWAY -> {
+      val holder = AutoCompleteViewHolder.NickViewHolder(
+        LayoutInflater.from(parent.context).inflate(
+          when (viewType) {
+            VIEWTYPE_AWAY -> R.layout.widget_nick_away
+            else          -> R.layout.widget_nick
+          }, parent, false
+        ),
+        clickListener = clickListener
+      )
+
+      holder.avatar.visibleIf(messageSettings.showAvatars)
+
+      holder
+    }
     else                                     -> throw IllegalArgumentException(
       "Invoked with wrong item type"
     )
@@ -75,11 +86,8 @@ class AutoCompleteAdapter(
       itemView: View,
       private val clickListener: ((String) -> Unit)? = null
     ) : AutoCompleteViewHolder(itemView) {
-      @BindView(R.id.modesContainer)
-      lateinit var modesContainer: View
-
-      @BindView(R.id.modes)
-      lateinit var modes: TextView
+      @BindView(R.id.avatar)
+      lateinit var avatar: ImageView
 
       @BindView(R.id.nick)
       lateinit var nick: TextView
@@ -101,11 +109,14 @@ class AutoCompleteAdapter(
       fun bindImpl(data: AutoCompleteItem.UserItem) {
         value = data.name
 
-        nick.text = data.nick
-        modes.text = data.modes
+        nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
         realname.text = data.realname
 
-        modes.visibleIf(data.modes.isNotBlank())
+        GlideApp.with(itemView)
+          .load(data.avatarUrl)
+          .apply(RequestOptions.circleCropTransform())
+          .placeholder(data.fallbackDrawable)
+          .into(avatar)
       }
     }
 
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 2a938902e..40034a1b2 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
@@ -2,6 +2,7 @@ package de.kuschku.quasseldroid.ui.chat.input
 
 import android.arch.lifecycle.LiveData
 import android.arch.lifecycle.Observer
+import android.graphics.Typeface
 import android.support.annotation.ColorInt
 import android.support.annotation.StringRes
 import android.support.v4.app.FragmentActivity
@@ -9,18 +10,25 @@ import android.support.v7.app.AppCompatActivity
 import android.support.v7.widget.*
 import android.text.Editable
 import android.text.InputType
+import android.text.SpannableString
 import android.text.TextWatcher
+import android.text.style.ForegroundColorSpan
+import android.text.style.StyleSpan
 import android.view.*
 import android.view.inputmethod.EditorInfo
 import butterknife.BindView
 import butterknife.ButterKnife
+import de.kuschku.libquassel.util.IrcUserUtils
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.AutoCompleteSettings
+import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
 import de.kuschku.quasseldroid.util.helper.*
+import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
 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 io.reactivex.Observable
 import io.reactivex.subjects.BehaviorSubject
@@ -37,9 +45,12 @@ class Editor(
   tabComplete: AppCompatImageButton,
   autoCompleteLists: List<RecyclerView>,
   formattingToolbar: Toolbar,
+  // Helpers
+  private val ircFormatDeserializer: IrcFormatDeserializer,
   // Settings
   private val appearanceSettings: AppearanceSettings,
   private val autoCompleteSettings: AutoCompleteSettings,
+  private val messageSettings: MessageSettings,
   // Listeners
   private val sendCallback: (Sequence<Pair<CharSequence, String>>) -> Unit,
   private val panelStateCallback: (Boolean) -> Unit
@@ -52,6 +63,17 @@ class Editor(
     else                      -> false
   }
 
+  private val senderColors = activity.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)
+    }
+  }
+
   private val lastWord = BehaviorSubject.createDefault(Pair("", IntRange.EMPTY))
   private val textWatcher = object : TextWatcher {
     override fun afterTextChanged(s: Editable?) {
@@ -137,6 +159,7 @@ class Editor(
     }.fold(0, Int::or)
 
     val autocompleteAdapter = AutoCompleteAdapter(
+      messageSettings,
       // This is still broken when mixing tab complete and UI auto complete
       formatHandler::autoComplete
     )
@@ -146,7 +169,49 @@ class Editor(
       val shouldShowResults = (autoCompleteSettings.auto && query.length >= 3) ||
                               (autoCompleteSettings.prefix && query.startsWith('@')) ||
                               (autoCompleteSettings.prefix && query.startsWith('#'))
-      autocompleteAdapter.submitList(if (shouldShowResults) it?.second.orEmpty() else emptyList())
+      val list = if (shouldShowResults) it?.second.orEmpty() else emptyList()
+      autocompleteAdapter.submitList(list.map {
+        if (it is AutoCompleteItem.UserItem) {
+          val nickName = it.nick
+          val senderColorIndex = IrcUserUtils.senderColor(nickName)
+          val initial = nickName.trimStart('-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\')
+            .firstOrNull()?.toUpperCase().toString()
+          val senderColor = senderColors[senderColorIndex]
+
+          fun formatNick(nick: CharSequence): CharSequence {
+            val spannableString = SpannableString(nick)
+            spannableString.setSpan(
+              ForegroundColorSpan(senderColor),
+              0,
+              nick.length,
+              SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
+            )
+            spannableString.setSpan(
+              StyleSpan(Typeface.BOLD),
+              0,
+              nick.length,
+              SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
+            )
+            return spannableString
+          }
+
+          it.copy(
+            displayNick = formatNick(it.nick),
+            fallbackDrawable = TextDrawable.builder().buildRound(initial, senderColor),
+            modes = when (messageSettings.showPrefix) {
+              MessageSettings.ShowPrefixMode.ALL ->
+                it.modes
+              else                               ->
+                it.modes.substring(0, Math.min(it.modes.length, 1))
+            },
+            realname = ircFormatDeserializer.formatString(
+              activity, it.realname.toString(), messageSettings.colorizeMirc
+            )
+          )
+        } else {
+          it
+        }
+      })
     })
 
     if (autoCompleteSettings.prefix || autoCompleteSettings.auto) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt
index a336d0f25..191abda65 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt
@@ -17,7 +17,7 @@ import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Flags
 import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.protocol.Message_Types
-import de.kuschku.libquassel.util.hasFlag
+import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.QuasselDatabase
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
index b735422fc..53a8f9e2a 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt
@@ -11,7 +11,8 @@ import android.util.TypedValue
 import de.kuschku.libquassel.protocol.Message.MessageType.*
 import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Type
-import de.kuschku.libquassel.util.hasFlag
+import de.kuschku.libquassel.util.IrcUserUtils
+import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.irc.HostmaskHelper
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.QuasselDatabase
@@ -21,7 +22,6 @@ import de.kuschku.quasseldroid.settings.MessageSettings.ShowPrefixMode
 import de.kuschku.quasseldroid.util.helper.styledAttributes
 import de.kuschku.quasseldroid.util.helper.visibleIf
 import de.kuschku.quasseldroid.util.irc.format.ContentFormatter
-import de.kuschku.quasseldroid.util.quassel.IrcUserUtils
 import de.kuschku.quasseldroid.util.ui.SpanFormatter
 import de.kuschku.quasseldroid.util.ui.TextDrawable
 import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage
@@ -420,7 +420,7 @@ class QuasselMessageRenderer @Inject constructor(
     if (colorize) {
       val senderColor = IrcUserUtils.senderColor(nick)
       spannableString.setSpan(
-        ForegroundColorSpan(senderColors[senderColor % senderColors.size]),
+        ForegroundColorSpan(senderColors[(senderColor + senderColors.size) % senderColors.size]),
         0,
         nick.length,
         SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt
index 4090fe00a..4f07b965b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt
@@ -6,14 +6,20 @@ import android.support.v7.widget.RecyclerView
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.ImageView
 import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
+import com.bumptech.glide.request.RequestOptions
+import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.util.helper.visibleIf
+import de.kuschku.quasseldroid.util.ui.SpanFormatter
 import de.kuschku.quasseldroid.viewmodel.data.IrcUserItem
 
 class NickListAdapter(
+  private val messageSettings: MessageSettings,
   private val clickListener: ((String) -> Unit)? = null
 ) : ListAdapter<IrcUserItem, NickListAdapter.NickViewHolder>(
   object : DiffUtil.ItemCallback<IrcUserItem>() {
@@ -23,8 +29,8 @@ class NickListAdapter(
     override fun areContentsTheSame(oldItem: IrcUserItem?, newItem: IrcUserItem?) =
       oldItem == newItem
   }) {
-  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
-    NickViewHolder(
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NickViewHolder {
+    val holder = NickViewHolder(
       LayoutInflater.from(parent.context).inflate(
         when (viewType) {
           VIEWTYPE_AWAY -> R.layout.widget_nick_away
@@ -34,6 +40,13 @@ class NickListAdapter(
       clickListener = clickListener
     )
 
+    holder.avatar.visibleIf(messageSettings.showAvatars)
+
+    return holder
+  }
+
+  operator fun get(position: Int): IrcUserItem? = super.getItem(position)
+
   override fun onBindViewHolder(holder: NickViewHolder, position: Int) =
     holder.bind(getItem(position))
 
@@ -47,11 +60,8 @@ class NickListAdapter(
     itemView: View,
     private val clickListener: ((String) -> Unit)? = null
   ) : RecyclerView.ViewHolder(itemView) {
-    @BindView(R.id.modesContainer)
-    lateinit var modesContainer: View
-
-    @BindView(R.id.modes)
-    lateinit var modes: TextView
+    @BindView(R.id.avatar)
+    lateinit var avatar: ImageView
 
     @BindView(R.id.nick)
     lateinit var nick: TextView
@@ -73,11 +83,15 @@ class NickListAdapter(
     fun bind(data: IrcUserItem) {
       user = data.nick
 
-      nick.text = data.nick
-      modes.text = data.modes
+      nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick)
       realname.text = data.realname
 
-      modes.visibleIf(data.modes.isNotBlank())
+
+      GlideApp.with(itemView)
+        .load(data.avatarUrl)
+        .apply(RequestOptions.circleCropTransform())
+        .placeholder(data.fallbackDrawable)
+        .into(avatar)
     }
   }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt
index bcbef6f39..4b399d478 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt
@@ -2,27 +2,39 @@ package de.kuschku.quasseldroid.ui.chat.nicks
 
 import android.arch.lifecycle.Observer
 import android.content.Intent
+import android.graphics.Typeface
 import android.os.Bundle
 import android.support.v7.widget.DefaultItemAnimator
 import android.support.v7.widget.LinearLayoutManager
 import android.support.v7.widget.RecyclerView
+import android.text.SpannableString
+import android.text.style.ForegroundColorSpan
+import android.text.style.StyleSpan
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import butterknife.BindView
 import butterknife.ButterKnife
+import com.bumptech.glide.Glide
+import com.bumptech.glide.ListPreloader
+import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
+import com.bumptech.glide.util.FixedPreloadSizeProvider
 import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.util.IrcUserUtils
 import de.kuschku.libquassel.util.helpers.value
 import de.kuschku.libquassel.util.irc.IrcCaseMappers
+import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.info.InfoActivity
 import de.kuschku.quasseldroid.ui.chat.info.InfoDescriptor
 import de.kuschku.quasseldroid.ui.chat.info.InfoType
+import de.kuschku.quasseldroid.util.helper.styledAttributes
 import de.kuschku.quasseldroid.util.helper.toLiveData
 import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
 import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
+import de.kuschku.quasseldroid.util.ui.TextDrawable
 import javax.inject.Inject
 
 class NickListFragment : ServiceBoundFragment() {
@@ -43,15 +55,54 @@ class NickListFragment : ServiceBoundFragment() {
     val view = inflater.inflate(R.layout.fragment_nick_list, container, false)
     ButterKnife.bind(this, view)
 
-    val nickListAdapter = NickListAdapter(clickListener)
+    val nickListAdapter = NickListAdapter(messageSettings, clickListener)
     nickList.adapter = nickListAdapter
     nickList.layoutManager = object : LinearLayoutManager(context) {
       override fun supportsPredictiveItemAnimations() = false
     }
     nickList.itemAnimator = DefaultItemAnimator()
+
+
+    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)
+      }
+    }
+
     viewModel.nickData.map {
       it.map {
+        val nickName = it.nick
+        val senderColorIndex = IrcUserUtils.senderColor(nickName)
+        val initial = nickName.trimStart('-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\')
+          .firstOrNull()?.toUpperCase().toString()
+        val senderColor = senderColors[senderColorIndex]
+
+
+        fun formatNick(nick: CharSequence): CharSequence {
+          val spannableString = SpannableString(nick)
+          spannableString.setSpan(
+            ForegroundColorSpan(senderColor),
+            0,
+            nick.length,
+            SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
+          )
+          spannableString.setSpan(
+            StyleSpan(Typeface.BOLD),
+            0,
+            nick.length,
+            SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
+          )
+          return spannableString
+        }
+
         it.copy(
+          displayNick = formatNick(it.nick),
+          fallbackDrawable = TextDrawable.builder().buildRound(initial, senderColor),
           modes = when (messageSettings.showPrefix) {
             MessageSettings.ShowPrefixMode.ALL ->
               it.modes
@@ -73,6 +124,23 @@ class NickListFragment : ServiceBoundFragment() {
       nickList.layoutManager.onRestoreInstanceState(getParcelable(KEY_STATE_LIST))
     }
 
+    val avatar_size = resources.getDimensionPixelSize(R.dimen.avatar_size)
+
+    val sizeProvider = FixedPreloadSizeProvider<String>(avatar_size, avatar_size)
+
+    val preloadModelProvider = object : ListPreloader.PreloadModelProvider<String> {
+      override fun getPreloadItems(position: Int) = nickListAdapter[position]?.avatarUrl?.let {
+        mutableListOf(it)
+      } ?: mutableListOf()
+
+      override fun getPreloadRequestBuilder(item: String) =
+        GlideApp.with(this@NickListFragment).load(item).override(avatar_size)
+    }
+
+    val preloader = RecyclerViewPreloader(Glide.with(this), preloadModelProvider, sizeProvider, 10)
+
+    nickList.addOnScrollListener(preloader)
+
     return view
   }
 
diff --git a/app/src/main/res/layout/fragment_nick_list.xml b/app/src/main/res/layout/fragment_nick_list.xml
index d1e0c34a7..58f05b5eb 100644
--- a/app/src/main/res/layout/fragment_nick_list.xml
+++ b/app/src/main/res/layout/fragment_nick_list.xml
@@ -6,4 +6,5 @@
   android:background="?attr/colorBackground"
   android:clipToPadding="false"
   android:fitsSystemWindows="true"
+  tools:listitem="@layout/widget_nick"
   tools:showIn="@layout/activity_main" />
diff --git a/app/src/main/res/layout/widget_chatmessage_plain.xml b/app/src/main/res/layout/widget_chatmessage_plain.xml
index 38c87d96b..85bf7eeb2 100644
--- a/app/src/main/res/layout/widget_chatmessage_plain.xml
+++ b/app/src/main/res/layout/widget_chatmessage_plain.xml
@@ -5,7 +5,8 @@
   android:layout_height="wrap_content"
   android:background="?attr/backgroundMenuItem"
   android:orientation="vertical"
-  android:textAppearance="?android:attr/textAppearanceListItemSmall">
+  android:textAppearance="?android:attr/textAppearanceListItemSmall"
+  tools:showIn="@layout/fragment_messages">
 
   <LinearLayout
     android:layout_width="match_parent"
@@ -45,6 +46,7 @@
         android:layout_height="@dimen/avatar_size"
         android:contentDescription="@string/label_avatar"
         android:visibility="gone"
+        tools:src="@tools:sample/avatars"
         tools:visibility="visible" />
     </FrameLayout>
 
@@ -105,8 +107,8 @@
           android:textColor="?attr/colorForegroundSecondary"
           android:textStyle="italic"
           android:visibility="gone"
-          tools:textSize="11.9sp"
           tools:text="@sample/messages.json/data/time"
+          tools:textSize="11.9sp"
           tools:visibility="visible" />
       </LinearLayout>
     </LinearLayout>
diff --git a/app/src/main/res/layout/widget_nick.xml b/app/src/main/res/layout/widget_nick.xml
index b54a3aeda..054915a7e 100644
--- a/app/src/main/res/layout/widget_nick.xml
+++ b/app/src/main/res/layout/widget_nick.xml
@@ -1,72 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-  xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
-  android:layout_height="56dp"
-  android:background="?selectableItemBackground"
-  android:clickable="true"
-  android:focusable="true"
+  android:layout_height="wrap_content"
+  android:background="?attr/backgroundMenuItem"
   android:orientation="horizontal"
-  android:paddingEnd="?listPreferredItemPaddingRight"
-  android:paddingLeft="?listPreferredItemPaddingLeft"
-  android:paddingRight="?listPreferredItemPaddingRight"
-  android:baselineAligned="false"
-  android:paddingStart="?listPreferredItemPaddingLeft">
+  android:paddingBottom="4dp"
+  android:paddingLeft="16dp"
+  android:paddingRight="16dp"
+  android:paddingTop="4dp"
+  android:textAppearance="?android:attr/textAppearanceListItemSmall"
+  tools:showIn="@layout/fragment_nick_list">
 
-  <FrameLayout
-    android:id="@+id/modesContainer"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
+  <ImageView
+    android:id="@+id/avatar"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="@dimen/avatar_size"
+    android:layout_gravity="center_vertical"
     android:layout_marginEnd="16dp"
     android:layout_marginRight="16dp"
-    android:minWidth="40dp">
-
-    <android.support.v7.widget.AppCompatTextView
-      android:id="@+id/modes"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="center_vertical"
-      android:layout_marginBottom="8dp"
-      android:layout_marginTop="8dp"
-      android:background="@drawable/bg_badge"
-      android:fontFamily="monospace"
-      android:gravity="center"
-      android:minHeight="24dp"
-      android:minWidth="24dp"
-      android:textColor="?colorBackground"
-      android:textSize="12sp"
-      android:textStyle="bold"
-      app:backgroundTint="@color/colorAccent"
-      tools:text="\@" />
-  </FrameLayout>
+    android:contentDescription="@string/label_avatar"
+    tools:src="@tools:sample/avatars" />
 
   <LinearLayout
-    android:layout_width="0dp"
-    android:layout_height="match_parent"
-    android:layout_weight="1"
-    android:gravity="center_vertical|start"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
     android:orientation="vertical">
 
     <TextView
       android:id="@+id/nick"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:fontFamily="sans-serif-medium"
-      android:gravity="center_vertical|start"
-      android:singleLine="true"
-      android:textColor="?colorTextPrimary"
+      android:textColor="?attr/colorTextPrimary"
       android:textSize="13sp"
-      tools:text="justJanne" />
+      tools:text="@sample/messages.json/data/sender" />
 
     <TextView
       android:id="@+id/realname"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:fontFamily="sans-serif"
-      android:gravity="center_vertical|start"
-      android:singleLine="true"
-      android:textColor="?colorTextSecondary"
+      android:textColor="?attr/colorTextSecondary"
       android:textSize="12sp"
-      tools:text="Janne Koschinski: https://kuschku.de/" />
+      tools:text="@sample/messages.json/data/sender"
+      tools:visibility="visible" />
   </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/widget_nick_away.xml b/app/src/main/res/layout/widget_nick_away.xml
index 276583648..8d4c1a90f 100644
--- a/app/src/main/res/layout/widget_nick_away.xml
+++ b/app/src/main/res/layout/widget_nick_away.xml
@@ -1,74 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-  xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
-  android:layout_height="56dp"
-  android:background="?selectableItemBackground"
-  android:clickable="true"
-  android:focusable="true"
+  android:layout_height="wrap_content"
+  android:background="?attr/backgroundMenuItem"
   android:orientation="horizontal"
-  android:paddingEnd="?listPreferredItemPaddingRight"
-  android:paddingLeft="?listPreferredItemPaddingLeft"
-  android:paddingRight="?listPreferredItemPaddingRight"
-  android:baselineAligned="false"
-  android:paddingStart="?listPreferredItemPaddingLeft">
+  android:paddingBottom="4dp"
+  android:paddingLeft="16dp"
+  android:paddingRight="16dp"
+  android:paddingTop="4dp"
+  android:textAppearance="?android:attr/textAppearanceListItemSmall"
+  tools:showIn="@layout/fragment_nick_list">
 
-  <FrameLayout
-    android:id="@+id/modesContainer"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
+  <ImageView
+    android:id="@+id/avatar"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="@dimen/avatar_size"
+    android:layout_gravity="center_vertical"
     android:layout_marginEnd="16dp"
     android:layout_marginRight="16dp"
-    android:minWidth="40dp">
-
-    <android.support.v7.widget.AppCompatTextView
-      android:id="@+id/modes"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="center_vertical"
-      android:layout_marginBottom="8dp"
-      android:layout_marginTop="8dp"
-      android:background="@drawable/bg_badge"
-      android:fontFamily="monospace"
-      android:gravity="center"
-      android:minHeight="24dp"
-      android:minWidth="24dp"
-      android:textColor="?colorBackground"
-      android:textSize="12sp"
-      android:textStyle="bold"
-      app:backgroundTint="@color/colorAccent"
-      tools:text="\@" />
-  </FrameLayout>
+    android:contentDescription="@string/label_avatar"
+    tools:src="@tools:sample/avatars" />
 
   <LinearLayout
-    android:layout_width="0dp"
-    android:layout_height="match_parent"
-    android:layout_weight="1"
-    android:gravity="center_vertical|start"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
     android:orientation="vertical">
 
     <TextView
       android:id="@+id/nick"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:fontFamily="sans-serif-medium"
-      android:gravity="center_vertical|start"
-      android:singleLine="true"
-      android:textColor="?colorTextSecondary"
+      android:textColor="?attr/colorTextSecondary"
       android:textSize="13sp"
       android:textStyle="italic"
-      tools:text="justJanne" />
+      tools:text="@sample/messages.json/data/sender" />
 
     <TextView
       android:id="@+id/realname"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:fontFamily="sans-serif"
-      android:gravity="center_vertical|start"
-      android:singleLine="true"
-      android:textColor="?colorTextSecondary"
+      android:textColor="?attr/colorTextSecondary"
       android:textSize="12sp"
       android:textStyle="italic"
-      tools:text="Janne Koschinski: https://kuschku.de/" />
+      tools:text="@sample/messages.json/data/sender"
+      tools:visibility="visible" />
   </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
index 6853dc8b4..f628ca914 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt
@@ -1,8 +1,8 @@
 package de.kuschku.libquassel.protocol
 
 import de.kuschku.libquassel.quassel.BufferInfo
-import de.kuschku.libquassel.util.Flag
-import de.kuschku.libquassel.util.Flags
+import de.kuschku.libquassel.util.flag.Flag
+import de.kuschku.libquassel.util.flag.Flags
 import org.threeten.bp.Instant
 
 class Message(
@@ -15,7 +15,8 @@ class Message(
   val senderPrefixes: String,
   val content: String
 ) {
-  enum class MessageType(override val bit: Int) : Flag<MessageType> {
+  enum class MessageType(override val bit: Int) :
+    Flag<MessageType> {
     Plain(0x00001),
     Notice(0x00002),
     Action(0x00004),
@@ -44,7 +45,8 @@ class Message(
     }
   }
 
-  enum class MessageFlag(override val bit: Int) : Flag<MessageFlag> {
+  enum class MessageFlag(override val bit: Int) :
+    Flag<MessageFlag> {
     Self(0x01),
     Highlight(0x02),
     Redirected(0x04),
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt
index dd3ec4116..02865205d 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt
@@ -5,8 +5,8 @@ import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.LegacyFeature
 import de.kuschku.libquassel.quassel.ProtocolFeature
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
-import de.kuschku.libquassel.util.Flags
-import de.kuschku.libquassel.util.ShortFlags
+import de.kuschku.libquassel.util.flag.Flags
+import de.kuschku.libquassel.util.flag.ShortFlags
 import de.kuschku.libquassel.util.helpers.deserializeString
 import java.nio.ByteBuffer
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt
index 69aade656..22e7ee810 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt
@@ -1,7 +1,7 @@
 package de.kuschku.libquassel.protocol.message
 
 import de.kuschku.libquassel.protocol.*
-import de.kuschku.libquassel.util.Flags
+import de.kuschku.libquassel.util.flag.Flags
 
 object ClientInitAckSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInitAck> {
   override fun serialize(data: HandshakeMessage.ClientInitAck) = mapOf(
diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt
index 9050cc750..0de96e427 100644
--- a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt
@@ -4,7 +4,7 @@ import de.kuschku.libquassel.protocol.QVariant
 import de.kuschku.libquassel.protocol.QVariantMap
 import de.kuschku.libquassel.protocol.Type
 import de.kuschku.libquassel.protocol.value
-import de.kuschku.libquassel.util.Flags
+import de.kuschku.libquassel.util.flag.Flags
 
 object ClientInitSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInit> {
   override fun serialize(data: HandshakeMessage.ClientInit) = mapOf(
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt
index b85e7ac3a..c5fcf18b3 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt
@@ -1,10 +1,10 @@
 package de.kuschku.libquassel.quassel
 
 import de.kuschku.libquassel.protocol.Buffer_Types
-import de.kuschku.libquassel.util.Flag
-import de.kuschku.libquassel.util.Flags
-import de.kuschku.libquassel.util.ShortFlag
-import de.kuschku.libquassel.util.ShortFlags
+import de.kuschku.libquassel.util.flag.Flag
+import de.kuschku.libquassel.util.flag.Flags
+import de.kuschku.libquassel.util.flag.ShortFlag
+import de.kuschku.libquassel.util.flag.ShortFlags
 
 data class BufferInfo(
   var bufferId: Int,
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt
index dd026c756..9243d109f 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt
@@ -1,7 +1,7 @@
 package de.kuschku.libquassel.quassel
 
-import de.kuschku.libquassel.util.Flag
-import de.kuschku.libquassel.util.Flags
+import de.kuschku.libquassel.util.flag.Flag
+import de.kuschku.libquassel.util.flag.Flags
 
 /**
  * A list of features that are optional in core and/or client, but need runtime checking
@@ -12,7 +12,8 @@ import de.kuschku.libquassel.util.Flags
  *
  * This list should be cleaned up after every protocol break, as we can assume them to be present then.
  */
-enum class LegacyFeature(override val bit: Int) : Flag<LegacyFeature> {
+enum class LegacyFeature(override val bit: Int) :
+  Flag<LegacyFeature> {
   SynchronizedMarkerLine(0x0001),
   SaslAuthentication(0x0002),
   SaslExternal(0x0004),
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt
index cadce1dd0..f3b7a22e2 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt
@@ -1,9 +1,10 @@
 package de.kuschku.libquassel.quassel
 
-import de.kuschku.libquassel.util.Flag
-import de.kuschku.libquassel.util.Flags
+import de.kuschku.libquassel.util.flag.Flag
+import de.kuschku.libquassel.util.flag.Flags
 
-enum class ProtocolFeature(override val bit: Int) : Flag<ProtocolFeature> {
+enum class ProtocolFeature(override val bit: Int) :
+  Flag<ProtocolFeature> {
   None(0x00),
   TLS(0x01),
   Compression(0x02);
diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt
index 03d07e2dd..cc015a74d 100644
--- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt
@@ -3,8 +3,8 @@ package de.kuschku.libquassel.quassel.syncables.interfaces
 import de.kuschku.libquassel.annotations.Slot
 import de.kuschku.libquassel.annotations.Syncable
 import de.kuschku.libquassel.protocol.*
-import de.kuschku.libquassel.util.Flag
-import de.kuschku.libquassel.util.Flags
+import de.kuschku.libquassel.util.flag.Flag
+import de.kuschku.libquassel.util.flag.Flags
 import java.nio.ByteBuffer
 
 @Syncable(name = "Network")
@@ -255,7 +255,8 @@ interface INetwork : ISyncableObject {
    * {@see http://www.irc.org/tech_docs/005.html}
    * {@see http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt}
    */
-  enum class ChannelModeType(override val bit: Int) : Flag<ChannelModeType> {
+  enum class ChannelModeType(override val bit: Int) :
+    Flag<ChannelModeType> {
     NOT_A_CHANMODE(0x00),
     A_CHANMODE(0x01),
     B_CHANMODE(0x02),
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 9a0de43cf..5b22f88e9 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt
@@ -13,7 +13,7 @@ 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.WARN
-import de.kuschku.libquassel.util.hasFlag
+import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.helpers.hexDump
 import de.kuschku.libquassel.util.helpers.write
 import de.kuschku.libquassel.util.nio.ChainedByteBuffer
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/CRCUtils.kt b/lib/src/main/java/de/kuschku/libquassel/util/CRCUtils.kt
similarity index 94%
rename from app/src/main/java/de/kuschku/quasseldroid/util/quassel/CRCUtils.kt
rename to lib/src/main/java/de/kuschku/libquassel/util/CRCUtils.kt
index b9fb401ab..998c248ad 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/CRCUtils.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/CRCUtils.kt
@@ -1,4 +1,4 @@
-package de.kuschku.quasseldroid.util.quassel
+package de.kuschku.libquassel.util
 
 object CRCUtils {
   fun qChecksum(data: ByteArray): Int {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/IrcUserUtils.kt b/lib/src/main/java/de/kuschku/libquassel/util/IrcUserUtils.kt
similarity index 97%
rename from app/src/main/java/de/kuschku/quasseldroid/util/quassel/IrcUserUtils.kt
rename to lib/src/main/java/de/kuschku/libquassel/util/IrcUserUtils.kt
index 403c63523..a2bf8f950 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/IrcUserUtils.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/IrcUserUtils.kt
@@ -1,4 +1,4 @@
-package de.kuschku.quasseldroid.util.quassel
+package de.kuschku.libquassel.util
 
 import java.util.*
 
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt b/lib/src/main/java/de/kuschku/libquassel/util/flag/Flag.kt
similarity index 69%
rename from lib/src/main/java/de/kuschku/libquassel/util/Flag.kt
rename to lib/src/main/java/de/kuschku/libquassel/util/flag/Flag.kt
index 7d0ae2df5..dd43df5d1 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/flag/Flag.kt
@@ -1,4 +1,4 @@
-package de.kuschku.libquassel.util
+package de.kuschku.libquassel.util.flag
 
 interface Flag<T> where T : Enum<T>, T : Flag<T> {
   val bit: Int
@@ -47,15 +47,19 @@ data class Flags<E>(
 
   companion object {
     inline fun <reified T> of(int: Int): Flags<T>
-      where T : Flag<T>, T : Enum<T> = Flags(int, enumValues())
+      where T : Flag<T>, T : Enum<T> = Flags(
+      int,
+      enumValues())
 
     inline fun <reified T> of(vararg flags: T): Flags<T>
       where T : Flag<T>, T : Enum<T> =
-      Flags(flags.map(Flag<T>::bit).distinct().sum(), enumValues())
+      Flags(flags.map(Flag<T>::bit).distinct().sum(),
+            enumValues())
 
     inline fun <reified T> of(flags: Iterable<T>): Flags<T>
       where T : Flag<T>, T : Enum<T> =
-      Flags(flags.map(Flag<T>::bit).distinct().sum(), enumValues())
+      Flags(flags.map(Flag<T>::bit).distinct().sum(),
+            enumValues())
   }
 
   interface Factory<E> where E : Flag<E>, E : Enum<E> {
@@ -74,40 +78,53 @@ infix fun <T> Flags<T>.hasFlag(which: T): Boolean where T : Enum<T>, T : Flag<T>
 }
 
 infix fun <T> Flags<T>.or(other: Int): Flags<T>
-  where T : kotlin.Enum<T>, T : Flag<T> = Flags(value or other)
+  where T : kotlin.Enum<T>, T : Flag<T> = Flags(
+  value or other)
 
 infix fun <T> Flags<T>.or(other: Flag<T>): Flags<T>
-  where T : kotlin.Enum<T>, T : Flag<T> = Flags(value or other.bit)
+  where T : kotlin.Enum<T>, T : Flag<T> = Flags(
+  value or other.bit)
 
 infix fun <T> Flags<T>.or(other: Flags<T>): Flags<T>
-  where T : kotlin.Enum<T>, T : Flag<T> = Flags(value or other.value)
+  where T : kotlin.Enum<T>, T : Flag<T> = Flags(
+  value or other.value)
 
 infix fun <T> Flags<T>.and(other: Int): Flags<T>
-  where T : kotlin.Enum<T>, T : Flag<T> = Flags(value and other)
+  where T : kotlin.Enum<T>, T : Flag<T> = Flags(
+  value and other)
 
 infix fun <T> Flags<T>.and(other: Flag<T>): Flags<T>
-  where T : kotlin.Enum<T>, T : Flag<T> = Flags(value and other.bit)
+  where T : kotlin.Enum<T>, T : Flag<T> = Flags(
+  value and other.bit)
 
 infix fun <T> Flags<T>.and(other: Flags<T>): Flags<T>
-  where T : kotlin.Enum<T>, T : Flag<T> = Flags(value and other.value)
+  where T : kotlin.Enum<T>, T : Flag<T> = Flags(
+  value and other.value)
 
 infix operator fun <T> Flags<T>.plus(other: Int): Flags<T>
-  where T : Enum<T>, T : Flag<T> = Flags(value or other)
+  where T : Enum<T>, T : Flag<T> = Flags(
+  value or other)
 
 infix operator fun <T> Flags<T>.plus(other: Flag<T>): Flags<T>
-  where T : Enum<T>, T : Flag<T> = Flags(value or other.bit)
+  where T : Enum<T>, T : Flag<T> = Flags(
+  value or other.bit)
 
 infix operator fun <T> Flags<T>.plus(other: Flags<T>): Flags<T>
-  where T : Enum<T>, T : Flag<T> = Flags(value or other.value)
+  where T : Enum<T>, T : Flag<T> = Flags(
+  value or other.value)
 
 infix operator fun <T> Flags<T>.minus(other: Int): Flags<T>
-  where T : Enum<T>, T : Flag<T> = Flags(value and other.inv())
+  where T : Enum<T>, T : Flag<T> = Flags(
+  value and other.inv())
 
 infix operator fun <T> Flags<T>.minus(other: Flag<T>): Flags<T>
-  where T : Enum<T>, T : Flag<T> = Flags(value and other.bit.inv())
+  where T : Enum<T>, T : Flag<T> = Flags(
+  value and other.bit.inv())
 
 infix operator fun <T> Flags<T>.minus(other: Flags<T>): Flags<T>
-  where T : Enum<T>, T : Flag<T> = Flags(value and other.value.inv())
+  where T : Enum<T>, T : Flag<T> = Flags(
+  value and other.value.inv())
 
 infix fun <T> Flags<T>.unset(which: T): Flags<T>
-  where T : Enum<T>, T : Flag<T> = Flags(value xor which.bit)
+  where T : Enum<T>, T : Flag<T> = Flags(
+  value xor which.bit)
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt b/lib/src/main/java/de/kuschku/libquassel/util/flag/LongFlag.kt
similarity index 69%
rename from lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt
rename to lib/src/main/java/de/kuschku/libquassel/util/flag/LongFlag.kt
index 7356adebc..9081e1eef 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/flag/LongFlag.kt
@@ -1,4 +1,4 @@
-package de.kuschku.libquassel.util
+package de.kuschku.libquassel.util.flag
 
 interface LongFlag<T> where T : Enum<T>, T : LongFlag<T> {
   val bit: Long
@@ -47,15 +47,19 @@ data class LongFlags<E>(
 
   companion object {
     inline fun <reified T> of(int: Long): LongFlags<T>
-      where T : LongFlag<T>, T : Enum<T> = LongFlags(int, enumValues())
+      where T : LongFlag<T>, T : Enum<T> = LongFlags(
+      int,
+      enumValues())
 
     inline fun <reified T> of(vararg flags: LongFlag<T>): LongFlags<T>
       where T : LongFlag<T>, T : Enum<T> =
-      LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), enumValues())
+      LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(),
+                enumValues())
 
     inline fun <reified T> of(flags: Iterable<T>): LongFlags<T>
       where T : LongFlag<T>, T : Enum<T> =
-      LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), enumValues())
+      LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(),
+                enumValues())
   }
 
   interface Factory<E> where E : LongFlag<E>, E : Enum<E> {
@@ -73,40 +77,53 @@ infix fun <T> LongFlags<T>.hasFlag(which: T): Boolean where T : Enum<T>, T : Lon
 }
 
 infix fun <T> LongFlags<T>.or(other: Long): LongFlags<T>
-  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value or other)
+  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(
+  value or other)
 
 infix fun <T> LongFlags<T>.or(other: LongFlag<T>): LongFlags<T>
-  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value or other.bit)
+  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(
+  value or other.bit)
 
 infix fun <T> LongFlags<T>.or(other: LongFlags<T>): LongFlags<T>
-  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value or other.value)
+  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(
+  value or other.value)
 
 infix fun <T> LongFlags<T>.and(other: Long): LongFlags<T>
-  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value and other)
+  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(
+  value and other)
 
 infix fun <T> LongFlags<T>.and(other: LongFlag<T>): LongFlags<T>
-  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value and other.bit)
+  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(
+  value and other.bit)
 
 infix fun <T> LongFlags<T>.and(other: LongFlags<T>): LongFlags<T>
-  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value and other.value)
+  where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(
+  value and other.value)
 
 infix operator fun <T> LongFlags<T>.plus(other: Long): LongFlags<T>
-  where T : Enum<T>, T : LongFlag<T> = LongFlags(value or other)
+  where T : Enum<T>, T : LongFlag<T> = LongFlags(
+  value or other)
 
 infix operator fun <T> LongFlags<T>.plus(other: LongFlag<T>): LongFlags<T>
-  where T : Enum<T>, T : LongFlag<T> = LongFlags(value or other.bit)
+  where T : Enum<T>, T : LongFlag<T> = LongFlags(
+  value or other.bit)
 
 infix operator fun <T> LongFlags<T>.plus(other: LongFlags<T>): LongFlags<T>
-  where T : Enum<T>, T : LongFlag<T> = LongFlags(value or other.value)
+  where T : Enum<T>, T : LongFlag<T> = LongFlags(
+  value or other.value)
 
 infix operator fun <T> LongFlags<T>.minus(other: Long): LongFlags<T>
-  where T : Enum<T>, T : LongFlag<T> = LongFlags(value and other.inv())
+  where T : Enum<T>, T : LongFlag<T> = LongFlags(
+  value and other.inv())
 
 infix operator fun <T> LongFlags<T>.minus(other: LongFlag<T>): LongFlags<T>
-  where T : Enum<T>, T : LongFlag<T> = LongFlags(value and other.bit.inv())
+  where T : Enum<T>, T : LongFlag<T> = LongFlags(
+  value and other.bit.inv())
 
 infix operator fun <T> LongFlags<T>.minus(other: LongFlags<T>): LongFlags<T>
-  where T : Enum<T>, T : LongFlag<T> = LongFlags(value and other.value.inv())
+  where T : Enum<T>, T : LongFlag<T> = LongFlags(
+  value and other.value.inv())
 
 infix fun <T> LongFlags<T>.unset(which: T): LongFlags<T>
-  where T : Enum<T>, T : LongFlag<T> = LongFlags(value xor which.bit)
\ No newline at end of file
+  where T : Enum<T>, T : LongFlag<T> = LongFlags(
+  value xor which.bit)
\ No newline at end of file
diff --git a/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt b/lib/src/main/java/de/kuschku/libquassel/util/flag/ShortFlag.kt
similarity index 72%
rename from lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt
rename to lib/src/main/java/de/kuschku/libquassel/util/flag/ShortFlag.kt
index c7271d111..2ef747380 100644
--- a/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/util/flag/ShortFlag.kt
@@ -1,4 +1,4 @@
-package de.kuschku.libquassel.util
+package de.kuschku.libquassel.util.flag
 
 import kotlin.experimental.and
 import kotlin.experimental.inv
@@ -52,15 +52,19 @@ data class ShortFlags<E>(
 
   companion object {
     inline fun <reified T> of(int: Short): ShortFlags<T>
-      where T : ShortFlag<T>, T : Enum<T> = ShortFlags(int, enumValues())
+      where T : ShortFlag<T>, T : Enum<T> = ShortFlags(
+      int,
+      enumValues())
 
     inline fun <reified T> of(vararg flags: ShortFlag<T>): ShortFlags<T>
       where T : ShortFlag<T>, T : Enum<T> =
-      ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), enumValues())
+      ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(),
+                 enumValues())
 
     inline fun <reified T> of(flags: Iterable<T>): ShortFlags<T>
       where T : ShortFlag<T>, T : Enum<T> =
-      ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), enumValues())
+      ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(),
+                 enumValues())
   }
 
   interface Factory<E> where E : ShortFlag<E>, E : Enum<E> {
@@ -78,40 +82,53 @@ infix fun <T> ShortFlags<T>.hasFlag(which: T): Boolean where T : Enum<T>, T : Sh
 }
 
 infix fun <T> ShortFlags<T>.or(other: Short): ShortFlags<T>
-  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value or other)
+  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value or other)
 
 infix fun <T> ShortFlags<T>.or(other: ShortFlag<T>): ShortFlags<T>
-  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.bit)
+  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value or other.bit)
 
 infix fun <T> ShortFlags<T>.or(other: ShortFlags<T>): ShortFlags<T>
-  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.value)
+  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value or other.value)
 
 infix fun <T> ShortFlags<T>.and(other: Short): ShortFlags<T>
-  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value and other)
+  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value and other)
 
 infix fun <T> ShortFlags<T>.and(other: ShortFlag<T>): ShortFlags<T>
-  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.bit)
+  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value and other.bit)
 
 infix fun <T> ShortFlags<T>.and(other: ShortFlags<T>): ShortFlags<T>
-  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.value)
+  where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value and other.value)
 
 infix operator fun <T> ShortFlags<T>.plus(other: Short): ShortFlags<T>
-  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value or other)
+  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value or other)
 
 infix operator fun <T> ShortFlags<T>.plus(other: ShortFlag<T>): ShortFlags<T>
-  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.bit)
+  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value or other.bit)
 
 infix operator fun <T> ShortFlags<T>.plus(other: ShortFlags<T>): ShortFlags<T>
-  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.value)
+  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value or other.value)
 
 infix operator fun <T> ShortFlags<T>.minus(other: Short): ShortFlags<T>
-  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.inv())
+  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value and other.inv())
 
 infix operator fun <T> ShortFlags<T>.minus(other: ShortFlag<T>): ShortFlags<T>
-  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.bit.inv())
+  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value and other.bit.inv())
 
 infix operator fun <T> ShortFlags<T>.minus(other: ShortFlags<T>): ShortFlags<T>
-  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.value.inv())
+  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value and other.value.inv())
 
 infix fun <T> ShortFlags<T>.unset(which: T): ShortFlags<T>
-  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value xor which.bit)
\ No newline at end of file
+  where T : Enum<T>, T : ShortFlag<T> = ShortFlags(
+  value xor which.bit)
\ 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 4ba1fec68..d65e28516 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
@@ -15,8 +15,8 @@ import de.kuschku.libquassel.session.ConnectionState
 import de.kuschku.libquassel.session.ISession
 import de.kuschku.libquassel.session.SessionManager
 import de.kuschku.libquassel.util.Optional
-import de.kuschku.libquassel.util.and
-import de.kuschku.libquassel.util.hasFlag
+import de.kuschku.libquassel.util.flag.and
+import de.kuschku.libquassel.util.flag.hasFlag
 import de.kuschku.libquassel.util.helpers.*
 import de.kuschku.quasseldroid.util.helper.combineLatest
 import de.kuschku.quasseldroid.util.helper.switchMapNotNull
@@ -181,7 +181,10 @@ class QuasselViewModel : ViewModel() {
                       lowestMode,
                       user.realName(),
                       user.isAway(),
-                      network.support("CASEMAPPING")
+                      network.support("CASEMAPPING"),
+                      Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let {
+                        "https://www.irccloud.com/avatar-redirect/$it"
+                      }
                     )
                   }
                 }
@@ -255,7 +258,10 @@ class QuasselViewModel : ViewModel() {
                             lowestMode,
                             user.realName(),
                             user.isAway(),
-                            network.support("CASEMAPPING")
+                            network.support("CASEMAPPING"),
+                            Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let {
+                              "https://www.irccloud.com/avatar-redirect/$it"
+                            }
                           )
                         }
                       }
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt
index 0aea3b45e..0b452a55b 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt
@@ -1,5 +1,6 @@
 package de.kuschku.quasseldroid.viewmodel.data
 
+import android.graphics.drawable.Drawable
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
 
@@ -20,7 +21,10 @@ sealed class AutoCompleteItem(open val name: String) : Comparable<AutoCompleteIt
     val lowestMode: Int,
     val realname: CharSequence,
     val away: Boolean,
-    val networkCasemapping: String?
+    val networkCasemapping: String?,
+    val displayNick: CharSequence? = null,
+    val avatarUrl: String? = null,
+    val fallbackDrawable: Drawable? = null
   ) : AutoCompleteItem(nick)
 
   data class ChannelItem(
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt
index 651699812..de3ec6672 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt
@@ -1,10 +1,15 @@
 package de.kuschku.quasseldroid.viewmodel.data
 
+import android.graphics.drawable.Drawable
+
 data class IrcUserItem(
   val nick: String,
   val modes: String,
   val lowestMode: Int,
   val realname: CharSequence,
   val away: Boolean,
-  val networkCasemapping: String?
+  val networkCasemapping: String?,
+  val avatarUrl: String? = null,
+  val fallbackDrawable: Drawable? = null,
+  val displayNick: CharSequence? = null
 )
\ No newline at end of file
-- 
GitLab