From f6680b543e9bd558d3f9b3931e4623491fcabc72 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sun, 10 Dec 2017 05:00:31 +0100
Subject: [PATCH] First implementation of chat message renderer

---
 app/build.gradle.kts                          |  42 +++---
 app/src/main/assets/org/threeten/bp/TZDB.dat  | Bin 0 -> 100361 bytes
 .../kuschku/quasseldroid_ng/QuasseldroidNG.kt |  11 +-
 .../persistence/QuasselDatabase.kt            |   9 ++
 .../ui/chat/BufferViewConfigFragment.kt       |   2 +-
 .../quasseldroid_ng/ui/chat/ChatActivity.kt   |   3 +-
 .../quasseldroid_ng/ui/chat/MessageAdapter.kt |  36 +++++
 .../ui/chat/MessageListFragment.kt            |  38 +----
 .../ui/chat/MessageRenderer.kt                |  13 ++
 .../ui/chat/QuasselMessageRenderer.kt         |  74 +++++++++
 .../ui/chat/QuasselMessageViewHolder.kt       |  22 +++
 .../quasseldroid_ng/ui/setup/SetupActivity.kt |   4 +-
 .../accounts/AccountSelectionActivity.kt      |   4 +-
 .../setup/accounts/AccountSelectionSlide.kt   |   2 +-
 .../util/backport/AndroidThreeTenBackport.kt  |  38 +++++
 .../quasseldroid_ng/util/quassel/CRCUtils.kt  |  44 ++++++
 .../util/quassel/IrcUserUtils.kt              |  53 +++++++
 .../util/service/BackendServiceConnection.kt  |  52 +++++++
 .../util/service/ServiceBoundActivity.kt      |  39 ++---
 .../util/service/ServiceBoundFragment.kt      |  36 +----
 .../util/ui/SpanFormatter.java                | 140 ++++++++++++++++++
 .../res/layout/widget_chatmessage_action.xml  |  54 +++++++
 .../res/layout/widget_chatmessage_error.xml   |  35 +++++
 .../res/layout/widget_chatmessage_plain.xml   |  33 +++++
 .../res/layout/widget_chatmessage_server.xml  |  35 +++++
 app/src/main/res/values/dimens.xml            |   5 +-
 build.gradle.kts                              |   4 +-
 lib/build.gradle.kts                          |   4 +-
 malheur/build.gradle.kts                      |  10 +-
 29 files changed, 712 insertions(+), 130 deletions(-)
 create mode 100644 app/src/main/assets/org/threeten/bp/TZDB.dat
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageAdapter.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageRenderer.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageRenderer.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageViewHolder.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/AndroidThreeTenBackport.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/CRCUtils.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/IrcUserUtils.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/util/service/BackendServiceConnection.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/SpanFormatter.java
 create mode 100644 app/src/main/res/layout/widget_chatmessage_action.xml
 create mode 100644 app/src/main/res/layout/widget_chatmessage_error.xml
 create mode 100644 app/src/main/res/layout/widget_chatmessage_plain.xml
 create mode 100644 app/src/main/res/layout/widget_chatmessage_server.xml

diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index bce3a7a92..c3df58fe4 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -16,7 +16,7 @@ plugins {
 
 android {
   compileSdkVersion(26)
-  buildToolsVersion("26.0.2")
+  buildToolsVersion("27.0.2")
 
   signingConfigs {
     val signing = project.rootProject.properties("signing.properties")
@@ -88,21 +88,21 @@ android {
   }
 }
 
-val appCompatVersion = "26.1.0"
-val appArchVersion = "1.0.0-rc1"
+val appCompatVersion = "27.0.2"
+val appArchVersion = "1.0.0"
 dependencies {
-  implementation(kotlin("stdlib", "1.1.61"))
+  implementation(kotlin("stdlib", "1.2.0"))
 
   implementation(appCompat("appcompat-v7"))
   implementation(appCompat("design"))
   implementation(appCompat("customtabs"))
   implementation(appCompat("cardview-v7"))
   implementation(appCompat("recyclerview-v7"))
-  implementation("com.android.support.constraint:constraint-layout:1.0.2")
+  implementation(appCompat("constraint", "constraint-layout", version = "1.0.2"))
 
-  implementation("com.github.StephenVinouze.AdvancedRecyclerView:core:1.1.6")
+  implementation("com.github.StephenVinouze.AdvancedRecyclerView", "core", "1.1.6")
 
-  implementation("io.reactivex.rxjava2:rxjava:2.1.3")
+  implementation("io.reactivex.rxjava2", "rxjava", "2.1.3")
 
   implementation(appArch("lifecycle", "extensions"))
   implementation(appArch("lifecycle", "reactivestreams"))
@@ -115,21 +115,25 @@ dependencies {
     exclude(group = "junit", module = "junit")
   }
 
-  implementation("org.threeten:threetenbp:1.3.6")
+  implementation("org.threeten", "threetenbp", "1.3.6", classifier = "no-tzdb")
 
-  implementation("com.jakewharton:butterknife:8.8.1")
-  kapt("com.jakewharton:butterknife-compiler:8.8.1")
+  implementation("com.jakewharton", "butterknife", "8.8.1")
+  kapt("com.jakewharton", "butterknife-compiler", "8.8.1")
 
-  implementation(project(":lib"))
+  implementation(project(":lib")) {
+    exclude(group = "org.threeten", module = "threetenbp")
+  }
   implementation(project(":malheur"))
 
+  debugImplementation("com.squareup.leakcanary", "leakcanary-android", "1.5.1")
+
   testImplementation(appArch("persistence.room", "testing"))
-  testImplementation("junit:junit:4.12")
+  testImplementation("junit", "junit", "4.12")
 
-  androidTestImplementation("com.android.support.test:runner:1.0.1")
-  androidTestImplementation("com.android.support.test:rules:1.0.1")
+  androidTestImplementation("com.android.support.test", "runner", "1.0.1")
+  androidTestImplementation("com.android.support.test", "rules", "1.0.1")
 
-  androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.1")
+  androidTestImplementation("com.android.support.test.espresso", "espresso-core", "3.0.1")
 }
 
 tasks.withType(KotlinCompile::class.java) {
@@ -168,8 +172,12 @@ fun Project.properties(fileName: String): Properties? {
  * @param module simple name of the AppCompat module, for example "cardview-v7".
  * @param version optional desired version, null implies [appCompatVersion].
  */
-fun appCompat(module: String, version: String? = null)
-  = "com.android.support:$module:${version ?: appCompatVersion}"
+fun appCompat(module: String, submodule: String? = null, version: String? = null)
+  = if (submodule != null) {
+  "com.android.support.$module:$submodule:${version ?: appCompatVersion}"
+} else {
+  "com.android.support:$module:${version ?: appCompatVersion}"
+}
 
 /**
  * Builds the dependency notation for the named AppArch [module] at the given [version].
diff --git a/app/src/main/assets/org/threeten/bp/TZDB.dat b/app/src/main/assets/org/threeten/bp/TZDB.dat
new file mode 100644
index 0000000000000000000000000000000000000000..5677059dc8b992b60ae88f75a82f14e80a1cbf70
GIT binary patch
literal 100361
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
B0fPVl

literal 0
HcmV?d00001

diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt
index f03aecc1f..6395cd025 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt
@@ -5,7 +5,9 @@ import android.content.pm.ShortcutInfo
 import android.content.pm.ShortcutManager
 import android.graphics.drawable.Icon
 import android.os.Build
+import com.squareup.leakcanary.LeakCanary
 import de.kuschku.malheur.CrashHandler
+import de.kuschku.quasseldroid_ng.util.backport.AndroidThreeTenBackport
 import de.kuschku.quasseldroid_ng.util.compatibility.AndroidCompatibilityUtils
 import de.kuschku.quasseldroid_ng.util.compatibility.AndroidLoggingHandler
 import de.kuschku.quasseldroid_ng.util.compatibility.AndroidStreamChannelFactory
@@ -13,7 +15,12 @@ import de.kuschku.quasseldroid_ng.util.helper.systemService
 
 class QuasseldroidNG : Application() {
   override fun onCreate() {
-    println("QuasseldroidNG::onCreate")
+    if (LeakCanary.isInAnalyzerProcess(this)) {
+      // This process is dedicated to LeakCanary for heap analysis.
+      // You should not init your app in this process.
+      return
+    }
+    LeakCanary.install(this)
 
     CrashHandler.init(
       application = this,
@@ -26,6 +33,8 @@ class QuasseldroidNG : Application() {
     AndroidLoggingHandler.inject()
     AndroidStreamChannelFactory.inject()
 
+    AndroidThreeTenBackport.init(this)
+
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
       systemService<ShortcutManager>().dynamicShortcuts = listOf(
         ShortcutInfo.Builder(this, "id1")
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt
index 89d9c7a8e..205530597 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt
@@ -4,6 +4,7 @@ import android.arch.paging.LivePagedListProvider
 import android.arch.persistence.room.*
 import android.content.Context
 import android.support.annotation.IntRange
+import android.support.v7.recyclerview.extensions.DiffCallback
 import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Type
 import org.threeten.bp.Instant
@@ -37,6 +38,14 @@ abstract class QuasselDatabase : RoomDatabase() {
         type)}, flag=${Message_Flag.of(
         flag)}, bufferId=$bufferId, sender='$sender', senderPrefixes='$senderPrefixes', content='$content')"
     }
+
+    object MessageDiffCallback : DiffCallback<DatabaseMessage>() {
+      override fun areContentsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage)
+        = oldItem == newItem
+
+      override fun areItemsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage)
+        = oldItem.messageId == newItem.messageId
+    }
   }
 
   @Dao
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt
index bcb8e99ed..5867f9f74 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/BufferViewConfigFragment.kt
@@ -92,7 +92,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
     chatListSpinner.adapter = adapter
     chatListSpinner.onItemSelectedListener = itemSelectedListener
 
-    chatList.adapter = BufferListAdapter(this, bufferList, handlerThread::post, activity::runOnUiThread, clickListener)
+    chatList.adapter = BufferListAdapter(this, bufferList, handlerThread::post, activity!!::runOnUiThread, clickListener)
     chatList.layoutManager = LinearLayoutManager(context)
     chatList.itemAnimator = DefaultItemAnimator()
     return view
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 17638610c..9b40316e0 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
@@ -62,7 +62,6 @@ class ChatActivity : ServiceBoundActivity() {
   private lateinit var database: QuasselDatabase
 
   override fun onCreate(savedInstanceState: Bundle?) {
-    println("ChatActivity::onCreate")
     handler.onCreate()
     super.onCreate(savedInstanceState)
     setContentView(R.layout.activity_main)
@@ -128,7 +127,7 @@ class ChatActivity : ServiceBoundActivity() {
       val status = it ?: ConnectionState.DISCONNECTED
 
       snackbar?.dismiss()
-      snackbar = Snackbar.make(window.decorView.rootView, status.name, Snackbar.LENGTH_SHORT)
+      snackbar = Snackbar.make(findViewById(R.id.contentMessages), status.name, Snackbar.LENGTH_SHORT)
       snackbar?.show()
     })
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageAdapter.kt
new file mode 100644
index 000000000..7422ad507
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageAdapter.kt
@@ -0,0 +1,36 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+import android.arch.paging.PagedListAdapter
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import de.kuschku.libquassel.protocol.Message_Flags
+import de.kuschku.libquassel.protocol.Message_Type
+import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
+
+class MessageAdapter(context: Context) : PagedListAdapter<QuasselDatabase.DatabaseMessage, QuasselMessageViewHolder>(QuasselDatabase.DatabaseMessage.MessageDiffCallback) {
+  val messageRenderer: MessageRenderer = QuasselMessageRenderer(context)
+
+  override fun onBindViewHolder(holder: QuasselMessageViewHolder, position: Int) {
+    getItem(position)?.let { messageRenderer.bind(holder, it) }
+  }
+
+  override fun getItemViewType(position: Int): Int {
+    return getItem(position)?.type ?: 0
+  }
+
+  private fun messageType(viewType: Int): Message_Type?
+    = Message_Type.of(viewType).enabledValues().firstOrNull()
+
+  private fun messageFlags(viewType: Int): Message_Flags
+    = Message_Flags.of()
+
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuasselMessageViewHolder {
+    return QuasselMessageViewHolder(LayoutInflater.from(parent.context).inflate(
+      messageRenderer.layout(messageType(viewType), messageFlags(viewType)),
+      parent,
+      false
+    ))
+  }
+}
+
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt
index 3e98bb186..7007b536f 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageListFragment.kt
@@ -4,16 +4,13 @@ import android.arch.lifecycle.LiveData
 import android.arch.lifecycle.MutableLiveData
 import android.arch.lifecycle.Observer
 import android.arch.paging.PagedList
-import android.arch.paging.PagedListAdapter
 import android.os.Bundle
-import android.support.v7.recyclerview.extensions.DiffCallback
 import android.support.v7.widget.DefaultItemAnimator
 import android.support.v7.widget.LinearLayoutManager
 import android.support.v7.widget.RecyclerView
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.BufferId
@@ -27,8 +24,6 @@ class MessageListFragment : ServiceBoundFragment() {
 
   private lateinit var database: QuasselDatabase
 
-  private val adapter = MessageAdapter()
-
   @BindView(R.id.messageList)
   lateinit var messageList: RecyclerView
 
@@ -36,7 +31,7 @@ class MessageListFragment : ServiceBoundFragment() {
     val view = inflater.inflate(R.layout.content_messages, container, false)
     ButterKnife.bind(this, view)
 
-    database = QuasselDatabase.Creator.init(context.applicationContext)
+    database = QuasselDatabase.Creator.init(context!!.applicationContext)
     val data = currentBuffer.switchMap {
       it.switchMap {
         database.message().findByBufferIdPaged(it).create(Int.MAX_VALUE,
@@ -49,6 +44,8 @@ class MessageListFragment : ServiceBoundFragment() {
       }
     }
 
+    val adapter = MessageAdapter(context!!)
+
     data.observe(this, Observer { list ->
       adapter.setList(list)
     })
@@ -59,33 +56,4 @@ class MessageListFragment : ServiceBoundFragment() {
 
     return view
   }
-}
-
-class MessageAdapter : PagedListAdapter<QuasselDatabase.DatabaseMessage, MessageViewHolder>(MessageDiffCallback) {
-  override fun onBindViewHolder(holder: MessageViewHolder?, position: Int) {
-    holder?.bind(getItem(position))
-  }
-
-  override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MessageViewHolder {
-    return MessageViewHolder(LayoutInflater.from(parent?.context).inflate(android.R.layout.simple_list_item_1, parent, false))
-  }
-}
-
-object MessageDiffCallback : DiffCallback<QuasselDatabase.DatabaseMessage>() {
-  override fun areContentsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage)
-    = oldItem == newItem
-
-  override fun areItemsTheSame(oldItem: QuasselDatabase.DatabaseMessage, newItem: QuasselDatabase.DatabaseMessage)
-    = oldItem.messageId == newItem.messageId
-}
-
-class MessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-  fun bind(message: QuasselDatabase.DatabaseMessage?) {
-    val text = (itemView as TextView)
-    if (message == null) {
-      text.text = "null"
-    } else {
-      text.text = "[${message.time}] <${message.senderPrefixes}${message.sender}> ${message.content}"
-    }
-  }
 }
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageRenderer.kt
new file mode 100644
index 000000000..4ca12c9fa
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageRenderer.kt
@@ -0,0 +1,13 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+import android.support.annotation.LayoutRes
+import de.kuschku.libquassel.protocol.Message_Flags
+import de.kuschku.libquassel.protocol.Message_Type
+import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
+
+interface MessageRenderer {
+  @LayoutRes
+  fun layout(type: Message_Type?, flags: Message_Flags): Int
+
+  fun bind(holder: QuasselMessageViewHolder, message: QuasselDatabase.DatabaseMessage)
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageRenderer.kt
new file mode 100644
index 000000000..751e67e35
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageRenderer.kt
@@ -0,0 +1,74 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+import android.content.Context
+import android.graphics.Typeface
+import android.text.SpannableString
+import android.text.format.DateFormat
+import android.text.style.ForegroundColorSpan
+import android.text.style.StyleSpan
+import de.kuschku.libquassel.protocol.Message.MessageType.*
+import de.kuschku.libquassel.protocol.Message_Flags
+import de.kuschku.libquassel.protocol.Message_Type
+import de.kuschku.quasseldroid_ng.R
+import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
+import de.kuschku.quasseldroid_ng.util.quassel.IrcUserUtils
+import de.kuschku.quasseldroid_ng.util.ui.SpanFormatter
+import org.threeten.bp.ZoneId
+import org.threeten.bp.format.DateTimeFormatter
+import java.text.SimpleDateFormat
+
+class QuasselMessageRenderer(context: Context) : MessageRenderer {
+  val timeFormatter = DateTimeFormatter.ofPattern((DateFormat.getTimeFormat(context) as SimpleDateFormat).toLocalizedPattern())
+  val senderColors: IntArray
+
+  init {
+    val typedArray = context.obtainStyledAttributes(intArrayOf(
+      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
+    ))
+    senderColors = IntArray(16) {
+      typedArray.getColor(it, 0)
+    }
+    typedArray.recycle()
+  }
+
+  override fun layout(type: Message_Type?, flags: Message_Flags)
+    = when (type) {
+    Nick, Notice, Mode, Join, Part, Quit, Kick, Kill, Server, Info, DayChange, Topic, NetsplitJoin,
+    NetsplitQuit, Invite -> R.layout.widget_chatmessage_server
+    Error -> R.layout.widget_chatmessage_error
+    Action -> R.layout.widget_chatmessage_action
+    Plain -> R.layout.widget_chatmessage_plain
+    else -> R.layout.widget_chatmessage_plain
+  }
+
+  override fun bind(holder: QuasselMessageViewHolder, message: QuasselDatabase.DatabaseMessage) {
+    holder.time.text = timeFormatter.format(message.time.atZone(ZoneId.systemDefault()))
+    holder.content.text = SpanFormatter.format(
+      "%s: %s",
+      formatNick(message.sender),
+      message.content
+    )
+  }
+
+  private fun formatNick(sender: String): CharSequence {
+    val nick = IrcUserUtils.nick(sender)
+    val senderColor = IrcUserUtils.senderColor(nick)
+    val spannableString = SpannableString(nick)
+    spannableString.setSpan(
+      ForegroundColorSpan(senderColors[senderColor % senderColors.size]),
+      0,
+      nick.length,
+      SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
+    )
+    spannableString.setSpan(
+      StyleSpan(Typeface.BOLD),
+      0,
+      nick.length,
+      SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
+    )
+    return spannableString
+  }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageViewHolder.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageViewHolder.kt
new file mode 100644
index 000000000..cf54d42c9
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/QuasselMessageViewHolder.kt
@@ -0,0 +1,22 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+import android.support.v7.widget.RecyclerView
+import android.text.method.LinkMovementMethod
+import android.view.View
+import android.widget.TextView
+import butterknife.BindView
+import butterknife.ButterKnife
+import de.kuschku.quasseldroid_ng.R
+
+class QuasselMessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+  @BindView(R.id.time)
+  lateinit var time: TextView
+
+  @BindView(R.id.content)
+  lateinit var content: TextView
+
+  init {
+    ButterKnife.bind(this, itemView)
+    content.movementMethod = LinkMovementMethod.getInstance()
+  }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt
index 5465c5995..9a943d1eb 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt
@@ -160,13 +160,13 @@ abstract class SetupActivity : AppCompatActivity() {
       list.add(fragment)
     }
 
-    override fun instantiateItem(container: ViewGroup?, position: Int): Any {
+    override fun instantiateItem(container: ViewGroup, position: Int): Any {
       val fragment = super.instantiateItem(container, position)
       storeNewFragment(position, fragment as SlideFragment)
       return fragment
     }
 
-    override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any?) {
+    override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
       retainedFragments.get(position)?.getData(result)
       retainedFragments.remove(position)
       super.destroyItem(container, position, `object`)
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
index ec5e12e1c..cb6891877 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
@@ -8,7 +8,7 @@ import android.os.Bundle
 import de.kuschku.quasseldroid_ng.Keys
 import de.kuschku.quasseldroid_ng.ui.chat.ChatActivity
 import de.kuschku.quasseldroid_ng.ui.setup.SetupActivity
-import de.kuschku.quasseldroid_ng.util.helper.editCommit
+import de.kuschku.quasseldroid_ng.util.helper.editApply
 
 class AccountSelectionActivity : SetupActivity() {
   companion object {
@@ -23,7 +23,7 @@ class AccountSelectionActivity : SetupActivity() {
 
   private lateinit var statusPreferences: SharedPreferences
   override fun onDone(data: Bundle) {
-    statusPreferences.editCommit {
+    statusPreferences.editApply {
       putLong(Keys.Status.selectedAccount, data.getLong(Keys.Status.selectedAccount, -1))
       putBoolean(Keys.Status.reconnect, true)
     }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt
index a0198fb1a..86b305133 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt
@@ -76,7 +76,7 @@ class AccountSelectionSlide : SlideFragment() {
   override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
     super.onActivityResult(requestCode, resultCode, data)
     if (requestCode == REQUEST_CREATE_FIRST && resultCode == Activity.RESULT_CANCELED) {
-      activity.finish()
+      activity?.finish()
     }
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/AndroidThreeTenBackport.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/AndroidThreeTenBackport.kt
new file mode 100644
index 000000000..04019a0f0
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/AndroidThreeTenBackport.kt
@@ -0,0 +1,38 @@
+package de.kuschku.quasseldroid_ng.util.backport
+
+import android.content.Context
+import org.threeten.bp.zone.TzdbZoneRulesProvider
+import org.threeten.bp.zone.ZoneRulesProvider
+import java.io.IOException
+import java.io.InputStream
+import java.util.concurrent.atomic.AtomicBoolean
+
+
+object AndroidThreeTenBackport {
+  private val initialized = AtomicBoolean()
+
+  fun init(context: Context) {
+    if (initialized.getAndSet(true)) {
+      return
+    }
+
+    val provider: TzdbZoneRulesProvider
+    var inputStream: InputStream? = null
+    try {
+      inputStream = context.assets.open("org/threeten/bp/TZDB.dat")
+      provider = TzdbZoneRulesProvider(inputStream)
+    } catch (e: IOException) {
+      throw IllegalStateException("TZDB.dat missing from assets.", e)
+    } finally {
+      if (inputStream != null) {
+        try {
+          inputStream.close()
+        } catch (ignored: IOException) {
+        }
+
+      }
+    }
+
+    ZoneRulesProvider.registerProvider(provider)
+  }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/CRCUtils.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/CRCUtils.kt
new file mode 100644
index 000000000..9a734a320
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/CRCUtils.kt
@@ -0,0 +1,44 @@
+package de.kuschku.quasseldroid_ng.util.quassel
+
+object CRCUtils {
+  fun qChecksum(data: ByteArray): Int {
+    var crc = 0xffff
+    val crcHighBitMask = 0x8000
+
+    for (b in data) {
+      val c = reflect(b.toInt(), 8)
+      var j = 0x80
+      while (j > 0) {
+        var highBit = crc and crcHighBitMask
+        crc = crc shl 1
+        if (c and j > 0) {
+          highBit = highBit xor crcHighBitMask
+        }
+        if (highBit > 0) {
+          crc = crc xor 0x1021
+        }
+        j = j shr 1
+      }
+    }
+
+    crc = reflect(crc, 16)
+    crc = crc xor 0xffff
+    crc = crc and 0xffff
+
+    return crc
+  }
+
+  private fun reflect(crc: Int, n: Int): Int {
+    var j = 1
+    var crcout = 0
+    var i = 1 shl n - 1
+    while (i > 0) {
+      if (crc and i > 0) {
+        crcout = crcout or j
+      }
+      j = j shl 1
+      i = i shr 1
+    }
+    return crcout
+  }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/IrcUserUtils.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/IrcUserUtils.kt
new file mode 100644
index 000000000..f9a348d9b
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/quassel/IrcUserUtils.kt
@@ -0,0 +1,53 @@
+package de.kuschku.quasseldroid_ng.util.quassel
+
+import java.util.*
+
+object IrcUserUtils {
+  fun senderColor(nick: String): Int {
+    return 0xf and CRCUtils.qChecksum(
+      nick.trimEnd('_').toLowerCase(Locale.US).toByteArray(Charsets.ISO_8859_1)
+    )
+  }
+
+  fun nick(hostmask: String): String {
+    return hostmask.substring(
+      0,
+      hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: hostmask.length
+    )
+  }
+
+  fun user(hostmask: String): String {
+    return hostmask.substring(
+      hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: 0,
+      hostmask.lastIndex('@') ?: hostmask.length
+    )
+  }
+
+  fun host(hostmask: String): String {
+    return hostmask.substring(
+      hostmask.lastIndex('@') ?: 0
+    )
+  }
+
+  fun mask(hostmask: String): String {
+    return hostmask.substring(
+      hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: 0
+    )
+  }
+
+  private fun String.firstIndex(char: Char, startIndex: Int? = null, ignoreCase: Boolean = false): Int? {
+    val lastIndex = indexOf(char, startIndex ?: 0, ignoreCase)
+    if (lastIndex < 0)
+      return null
+    else
+      return lastIndex
+  }
+
+  private fun String.lastIndex(char: Char, startIndex: Int? = null, ignoreCase: Boolean = false): Int? {
+    val lastIndex = lastIndexOf(char, startIndex ?: lastIndex, ignoreCase)
+    if (lastIndex < 0)
+      return null
+    else
+      return lastIndex
+  }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/BackendServiceConnection.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/BackendServiceConnection.kt
new file mode 100644
index 000000000..6dff17f6a
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/BackendServiceConnection.kt
@@ -0,0 +1,52 @@
+package de.kuschku.quasseldroid_ng.util.service
+
+import android.arch.lifecycle.MutableLiveData
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
+import de.kuschku.libquassel.session.Backend
+import de.kuschku.quasseldroid_ng.service.QuasselService
+
+class BackendServiceConnection : ServiceConnection {
+  var bound = false
+  val backend = MutableLiveData<Backend?>()
+
+  var context: Context? = null
+
+  override fun onServiceDisconnected(component: ComponentName?) {
+    bound = false
+    when (component) {
+      ComponentName(context, QuasselService::class.java) -> {
+        backend.value = null
+      }
+    }
+  }
+
+  override fun onServiceConnected(component: ComponentName?, binder: IBinder?) {
+    bound = true
+    when (component) {
+      ComponentName(context, QuasselService::class.java) ->
+        if (binder is QuasselService.QuasselBinder) {
+          backend.value = binder.backend
+        }
+    }
+  }
+
+  fun start(intent: Intent = Intent(context, QuasselService::class.java)) {
+    context?.startService(intent)
+  }
+
+  fun bind(intent: Intent = Intent(context, QuasselService::class.java), flags: Int = 0) {
+    context?.bindService(intent, this, flags)
+  }
+
+  fun stop(intent: Intent = Intent(context, QuasselService::class.java)) {
+    context?.stopService(intent)
+  }
+
+  fun unbind() {
+    if (bound) context?.unbindService(this)
+  }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt
index 9c8598786..ef9518e58 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt
@@ -1,49 +1,30 @@
 package de.kuschku.quasseldroid_ng.util.service
 
-import android.arch.lifecycle.MutableLiveData
-import android.content.ComponentName
-import android.content.Intent
-import android.content.ServiceConnection
+import android.arch.lifecycle.LiveData
 import android.os.Bundle
-import android.os.IBinder
 import android.support.annotation.ColorRes
 import android.support.annotation.DrawableRes
 import android.support.v7.app.AppCompatActivity
 import de.kuschku.libquassel.session.Backend
 import de.kuschku.quasseldroid_ng.R
-import de.kuschku.quasseldroid_ng.service.QuasselService
 import de.kuschku.quasseldroid_ng.util.helper.updateRecentsHeaderIfExisting
 
 abstract class ServiceBoundActivity : AppCompatActivity() {
-  protected val backend = MutableLiveData<Backend?>()
   @DrawableRes
   protected val icon: Int = R.mipmap.ic_launcher
   @ColorRes
   protected val recentsHeaderColor: Int = R.color.colorPrimaryDark
 
-  private val connection = object : ServiceConnection {
-    override fun onServiceDisconnected(component: ComponentName?) {
-      when (component) {
-        ComponentName(application, QuasselService::class.java) -> {
-          backend.value = null
-        }
-      }
-    }
+  private val connection = BackendServiceConnection()
 
-    override fun onServiceConnected(component: ComponentName?, binder: IBinder?) {
-      when (component) {
-        ComponentName(application, QuasselService::class.java) ->
-          if (binder is QuasselService.QuasselBinder) {
-            backend.value = binder.backend
-          }
-      }
-    }
-  }
+  val backend: LiveData<Backend?>
+    get() = connection.backend
 
   override fun onCreate(savedInstanceState: Bundle?) {
+    connection.context = this
     setTheme(R.style.Theme_ChatTheme_Quassel_Light)
     super.onCreate(savedInstanceState)
-    startService(Intent(this, QuasselService::class.java))
+    connection.start()
     updateRecentsHeader()
   }
 
@@ -56,17 +37,17 @@ abstract class ServiceBoundActivity : AppCompatActivity() {
   }
 
   override fun onStart() {
-    bindService(Intent(this, QuasselService::class.java), connection, 0)
+    connection.bind()
     super.onStart()
   }
 
   override fun onStop() {
     super.onStop()
-    unbindService(connection)
+    connection.unbind()
   }
 
   protected fun stopService() {
-    unbindService(connection)
-    stopService(Intent(this, QuasselService::class.java))
+    connection.unbind()
+    connection.stop()
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt
index 87c260f11..6d42d7227 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundFragment.kt
@@ -1,49 +1,29 @@
 package de.kuschku.quasseldroid_ng.util.service
 
-import android.arch.lifecycle.MutableLiveData
-import android.content.ComponentName
-import android.content.Intent
-import android.content.ServiceConnection
+import android.arch.lifecycle.LiveData
 import android.os.Bundle
-import android.os.IBinder
 import android.support.v4.app.Fragment
 import de.kuschku.libquassel.session.Backend
-import de.kuschku.quasseldroid_ng.service.QuasselService
 
 abstract class ServiceBoundFragment : Fragment() {
-  protected val backend = MutableLiveData<Backend?>()
+  private var connection = BackendServiceConnection()
 
-  private val connection = object : ServiceConnection {
-    override fun onServiceDisconnected(component: ComponentName?) {
-      when (component) {
-        ComponentName(context.applicationContext, QuasselService::class.java) -> {
-          backend.value = null
-        }
-      }
-    }
-
-    override fun onServiceConnected(component: ComponentName?, binder: IBinder?) {
-      when (component) {
-        ComponentName(context.applicationContext, QuasselService::class.java) ->
-          if (binder is QuasselService.QuasselBinder) {
-            backend.value = binder.backend
-          }
-      }
-    }
-  }
+  val backend: LiveData<Backend?>
+    get() = connection.backend
 
   override fun onCreate(savedInstanceState: Bundle?) {
+    connection.context = context
     super.onCreate(savedInstanceState)
-    context.startService(Intent(context, QuasselService::class.java))
+    connection.start()
   }
 
   override fun onStart() {
-    context.bindService(Intent(context, QuasselService::class.java), connection, 0)
+    connection.bind()
     super.onStart()
   }
 
   override fun onStop() {
     super.onStop()
-    context.unbindService(connection)
+    connection.unbind()
   }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/SpanFormatter.java b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/SpanFormatter.java
new file mode 100644
index 000000000..31f342ec7
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/SpanFormatter.java
@@ -0,0 +1,140 @@
+/*
+ * QuasselDroid - Quassel client for Android
+ * Copyright (C) 2016 Janne Koschinski
+ * Copyright (C) 2016 Ken Børge Viktil
+ * Copyright (C) 2016 Magnus Fjell
+ * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+* Copyright © 2014 George T. Steel
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package de.kuschku.quasseldroid_ng.util.ui;
+
+import android.support.annotation.NonNull;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
+
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Provides {@link String#format} style functions that work with {@link Spanned} strings and preserve formatting.
+ *
+ * @author George T. Steel
+ */
+public class SpanFormatter {
+    private static final Pattern FORMAT_SEQUENCE = Pattern.compile("%([0-9]+\\$|<?)([^a-zA-z%]*)([[a-zA-Z%]&&[^tT]]|[tT][a-zA-Z])");
+
+    private SpanFormatter() {
+    }
+
+    /**
+     * Version of {@link String#format(String, Object...)} that works on {@link Spanned} strings to preserve rich text formatting.
+     * Both the {@code format} as well as any {@code %s args} can be Spanned and will have their formatting preserved.
+     * Due to the way {@link Spannable}s work, any argument's spans will can only be included <b>once</b> in the result.
+     * Any duplicates will appear as text only.
+     *
+     * @param format the format string (see {@link java.util.Formatter#format})
+     * @param args   the list of arguments passed to the formatter. If there are
+     *               more arguments than required by {@code format},
+     *               additional arguments are ignored.
+     * @return the formatted string (with spans).
+     */
+    @NonNull
+    public static SpannedString format(@NonNull CharSequence format, Object... args) {
+        return format(Locale.getDefault(), format, args);
+    }
+
+    /**
+     * Version of {@link String#format(Locale, String, Object...)} that works on {@link Spanned} strings to preserve rich text formatting.
+     * Both the {@code format} as well as any {@code %s args} can be Spanned and will have their formatting preserved.
+     * Due to the way {@link Spannable}s work, any argument's spans will can only be included <b>once</b> in the result.
+     * Any duplicates will appear as text only.
+     *
+     * @param locale the locale to apply; {@code null} value means no localization.
+     * @param format the format string (see {@link java.util.Formatter#format})
+     * @param args   the list of arguments passed to the formatter.
+     * @return the formatted string (with spans).
+     * @see String#format(Locale, String, Object...)
+     */
+    @NonNull
+    public static SpannedString format(@NonNull Locale locale, @NonNull CharSequence format, Object... args) {
+        SpannableStringBuilder out = new SpannableStringBuilder(format);
+
+        int i = 0;
+        int argAt = -1;
+
+        while (i < out.length()) {
+            Matcher m = FORMAT_SEQUENCE.matcher(out);
+            if (!m.find(i)) break;
+            i = m.start();
+            int exprEnd = m.end();
+
+            String argTerm = m.group(1);
+            String modTerm = m.group(2);
+            String typeTerm = m.group(3);
+
+            CharSequence cookedArg;
+
+            if (typeTerm.equals("%")) {
+                cookedArg = "%";
+            } else {
+                int argIdx;
+                switch (argTerm) {
+                    case "":
+                        argIdx = ++argAt;
+                        break;
+                    case "<":
+                        argIdx = argAt;
+                        break;
+                    default:
+                        argIdx = Integer.parseInt(argTerm.substring(0, argTerm.length() - 1)) - 1;
+                        break;
+                }
+
+                Object argItem = args[argIdx];
+
+                if (typeTerm.equals("s") && argItem instanceof Spanned) {
+                    cookedArg = (Spanned) argItem;
+                } else {
+                    cookedArg = String.format(locale, "%" + modTerm + typeTerm, argItem);
+                }
+            }
+
+            out.replace(i, exprEnd, cookedArg);
+            i += cookedArg.length();
+        }
+
+        return new SpannedString(out);
+    }
+}
diff --git a/app/src/main/res/layout/widget_chatmessage_action.xml b/app/src/main/res/layout/widget_chatmessage_action.xml
new file mode 100644
index 000000000..b4271dd33
--- /dev/null
+++ b/app/src/main/res/layout/widget_chatmessage_action.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ QuasselDroid - Quassel client for Android
+  ~ Copyright (C) 2016 Janne Koschinski
+  ~ Copyright (C) 2016 Ken Børge Viktil
+  ~ Copyright (C) 2016 Magnus Fjell
+  ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify it
+  ~ under the terms of the GNU General Public License as published by the Free
+  ~ Software Foundation, either version 3 of the License, or (at your option)
+  ~ any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License along
+  ~ with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clickable="true"
+    android:focusable="true"
+    android:gravity="top"
+    android:orientation="horizontal"
+    android:paddingBottom="@dimen/message_vertical"
+    android:paddingEnd="@dimen/message_horizontal"
+    android:paddingLeft="@dimen/message_horizontal"
+    android:paddingRight="@dimen/message_horizontal"
+    android:paddingStart="@dimen/message_horizontal"
+    android:paddingTop="@dimen/message_vertical"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall">
+
+    <TextView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/message_horizontal"
+        android:layout_marginRight="@dimen/message_horizontal"
+        android:textColor="?attr/colorForegroundSecondary"
+        android:typeface="monospace" />
+
+    <TextView
+        android:id="@+id/content"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textColor="?attr/colorForegroundAction"
+        android:textIsSelectable="true"
+        android:textStyle="italic" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_error.xml b/app/src/main/res/layout/widget_chatmessage_error.xml
new file mode 100644
index 000000000..44e42f1cd
--- /dev/null
+++ b/app/src/main/res/layout/widget_chatmessage_error.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?attr/colorBackgroundSecondary"
+    android:clickable="true"
+    android:focusable="true"
+    android:gravity="top"
+    android:orientation="horizontal"
+    android:paddingBottom="@dimen/message_vertical"
+    android:paddingEnd="@dimen/message_horizontal"
+    android:paddingLeft="@dimen/message_horizontal"
+    android:paddingRight="@dimen/message_horizontal"
+    android:paddingStart="@dimen/message_horizontal"
+    android:paddingTop="@dimen/message_vertical"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall">
+
+    <TextView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/message_horizontal"
+        android:layout_marginRight="@dimen/message_horizontal"
+        android:textColor="?attr/colorForegroundSecondary"
+        android:typeface="monospace" />
+
+    <TextView
+        android:id="@+id/content"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textColor="?attr/colorForegroundError"
+        android:textIsSelectable="true"
+        android:textStyle="italic" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_plain.xml b/app/src/main/res/layout/widget_chatmessage_plain.xml
new file mode 100644
index 000000000..0e16b66a1
--- /dev/null
+++ b/app/src/main/res/layout/widget_chatmessage_plain.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clickable="true"
+    android:focusable="true"
+    android:gravity="top"
+    android:orientation="horizontal"
+    android:paddingBottom="@dimen/message_vertical"
+    android:paddingEnd="@dimen/message_horizontal"
+    android:paddingLeft="@dimen/message_horizontal"
+    android:paddingRight="@dimen/message_horizontal"
+    android:paddingStart="@dimen/message_horizontal"
+    android:paddingTop="@dimen/message_vertical"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall">
+
+    <TextView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/message_horizontal"
+        android:layout_marginRight="@dimen/message_horizontal"
+        android:textColor="?attr/colorForegroundSecondary"
+        android:typeface="monospace" />
+
+    <TextView
+        android:id="@+id/content"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textColor="?attr/colorForeground"
+        android:textIsSelectable="true" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_server.xml b/app/src/main/res/layout/widget_chatmessage_server.xml
new file mode 100644
index 000000000..40613e00c
--- /dev/null
+++ b/app/src/main/res/layout/widget_chatmessage_server.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?attr/colorBackgroundSecondary"
+    android:clickable="true"
+    android:focusable="true"
+    android:gravity="top"
+    android:orientation="horizontal"
+    android:paddingBottom="@dimen/message_vertical"
+    android:paddingEnd="@dimen/message_horizontal"
+    android:paddingLeft="@dimen/message_horizontal"
+    android:paddingRight="@dimen/message_horizontal"
+    android:paddingStart="@dimen/message_horizontal"
+    android:paddingTop="@dimen/message_vertical"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall">
+
+    <TextView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/message_horizontal"
+        android:layout_marginRight="@dimen/message_horizontal"
+        android:textColor="?attr/colorForegroundSecondary"
+        android:typeface="monospace" />
+
+    <TextView
+        android:id="@+id/content"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textColor="?attr/colorForegroundSecondary"
+        android:textIsSelectable="true"
+        android:textStyle="italic" />
+</LinearLayout>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 4b0853092..dd9f8a6b1 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,3 +1,6 @@
 <resources>
-  <dimen name="navigation_drawer_max_width">320dp</dimen>
+    <dimen name="navigation_drawer_max_width">320dp</dimen>
+
+    <dimen name="message_horizontal">8dp</dimen>
+    <dimen name="message_vertical">2dp</dimen>
 </resources>
diff --git a/build.gradle.kts b/build.gradle.kts
index 98bb71717..b5ff130ac 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,8 +5,8 @@ buildscript {
   }
   dependencies {
     classpath("com.android.tools.build:gradle:3.0.1")
-    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.61")
-    classpath("org.jetbrains.kotlin:kotlin-android-extensions:1.1.61")
+    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.0")
+    classpath("org.jetbrains.kotlin:kotlin-android-extensions:1.2.0")
   }
 }
 
diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts
index c39ec3973..0161971e9 100644
--- a/lib/build.gradle.kts
+++ b/lib/build.gradle.kts
@@ -11,10 +11,10 @@ plugins {
 
 val appCompatVersion = "26.1.0"
 dependencies {
-  implementation(kotlin("stdlib", "1.1.61"))
+  implementation(kotlin("stdlib", "1.2.0"))
 
   implementation(appCompat("support-annotations"))
-  implementation("org.threeten:threetenbp:1.3.6")
+  implementation("org.threeten", "threetenbp", "1.3.6")
   implementation("io.reactivex.rxjava2:rxjava:2.1.3")
 
   implementation(project(":invokerannotations"))
diff --git a/malheur/build.gradle.kts b/malheur/build.gradle.kts
index d1bdc4450..38e8818bd 100644
--- a/malheur/build.gradle.kts
+++ b/malheur/build.gradle.kts
@@ -1,7 +1,3 @@
-import org.gradle.kotlin.dsl.apply
-import org.gradle.kotlin.dsl.dependencies
-import org.gradle.kotlin.dsl.kotlin
-
 plugins {
   id("com.android.library")
   kotlin("android")
@@ -10,7 +6,7 @@ plugins {
 
 android {
   compileSdkVersion(26)
-  buildToolsVersion("26.0.2")
+  buildToolsVersion("27.0.2")
 
   defaultConfig {
     minSdkVersion(9)
@@ -21,7 +17,7 @@ android {
 }
 
 dependencies {
-  implementation(kotlin("stdlib", "1.1.61"))
+  implementation(kotlin("stdlib", "1.2.0"))
 
-  implementation("com.google.code.gson:gson:2.2.4")
+  implementation("com.google.code.gson", "gson", "2.2.4")
 }
-- 
GitLab