From a67166b2598a8074c1d8f01cf9abed43cd4a751a Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Mon, 2 Apr 2018 13:43:56 +0200
Subject: [PATCH] Improve rendering performance of markerline

---
 .../chat/messages/DayChangeItemDecoration.kt  |   8 +-
 .../chat/messages/MarkerLineItemDecoration.kt |  65 +++++++
 .../ui/chat/messages/MessageAdapter.kt        |   6 -
 .../ui/chat/messages/MessageListFragment.kt   |   3 +
 .../res/layout/widget_chatmessage_action.xml  | 103 +++++------
 .../layout/widget_chatmessage_daychange.xml   |   4 -
 .../res/layout/widget_chatmessage_error.xml   |  99 +++++-----
 .../res/layout/widget_chatmessage_info.xml    | 101 +++++------
 .../res/layout/widget_chatmessage_notice.xml  |  99 +++++-----
 .../res/layout/widget_chatmessage_plain.xml   | 169 ++++++++----------
 .../res/layout/widget_chatmessage_server.xml  |  99 +++++-----
 app/src/main/res/values/dimens.xml            |   2 +
 app/src/main/res/values/ids.xml               |   2 +
 13 files changed, 372 insertions(+), 388 deletions(-)
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MarkerLineItemDecoration.kt

diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DayChangeItemDecoration.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DayChangeItemDecoration.kt
index 660579438..e889eb159 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DayChangeItemDecoration.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/DayChangeItemDecoration.kt
@@ -16,7 +16,7 @@ import org.threeten.bp.temporal.ChronoUnit
 class DayChangeItemDecoration(private val adapter: MessageAdapter) :
   RecyclerView.ItemDecoration() {
   private val dayChangeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
-  private val mBounds = Rect()
+  private val bounds = Rect()
 
   override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
     c.save()
@@ -35,9 +35,9 @@ class DayChangeItemDecoration(private val adapter: MessageAdapter) :
     for (i in 0 until childCount) {
       val child = parent.getChildAt(i)
       if (child.getTag(R.id.tag_daychange) == true) {
-        parent.getDecoratedBoundsWithMargins(child, mBounds)
-        val bottom = mBounds.bottom + Math.round(child.translationY)
-        val top = mBounds.top + Math.round(child.translationY)
+        parent.getDecoratedBoundsWithMargins(child, bounds)
+        val bottom = bounds.bottom + Math.round(child.translationY)
+        val top = bounds.top + Math.round(child.translationY)
         val layout = child.getTag(R.id.tag_daychange_layout) as View
         c.save()
         c.clipRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MarkerLineItemDecoration.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MarkerLineItemDecoration.kt
new file mode 100644
index 000000000..a17722a03
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MarkerLineItemDecoration.kt
@@ -0,0 +1,65 @@
+package de.kuschku.quasseldroid.ui.chat.messages
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.Rect
+import android.support.annotation.AttrRes
+import android.support.annotation.DimenRes
+import android.support.v7.widget.RecyclerView
+import android.view.View
+import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.util.helper.styledAttributes
+
+class MarkerLineItemDecoration(
+  private val adapter: MessageAdapter,
+  context: Context,
+  @DimenRes height: Int,
+  @AttrRes markerlineColor: Int
+) : RecyclerView.ItemDecoration() {
+  private val bounds = Rect()
+  private val height = context.resources.getDimensionPixelSize(height)
+  private val color = context.theme.styledAttributes(markerlineColor) {
+    Paint().apply {
+      color = getColor(0, 0)
+    }
+  }
+
+  override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
+    c.save()
+    val left: Int
+    val right: Int
+    if (parent.clipToPadding) {
+      left = parent.paddingLeft
+      right = parent.width - parent.paddingRight
+      c.clipRect(left, parent.paddingTop, right, parent.height - parent.paddingBottom)
+    } else {
+      left = 0
+      right = parent.width
+    }
+
+    val childCount = parent.childCount
+    for (i in 0 until childCount) {
+      val child = parent.getChildAt(i)
+      if (child.getTag(R.id.tag_markerline) == true) {
+        parent.getDecoratedBoundsWithMargins(child, bounds)
+        val bottom = bounds.bottom + Math.round(child.translationY)
+        val top = bottom - height
+        c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), color)
+      }
+    }
+    c.restore()
+  }
+
+  override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView,
+                              state: RecyclerView.State) {
+    adapter[parent.getChildAdapterPosition(view)]?.let {
+      if (it.isMarkerLine) {
+        view.setTag(R.id.tag_markerline, true)
+        outRect.set(0, 0, height, 0)
+      } else {
+        view.setTag(R.id.tag_markerline, false)
+      }
+    }
+  }
+}
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 0cbe4e1db..2d9731451 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
@@ -22,7 +22,6 @@ import de.kuschku.quasseldroid.GlideApp
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.QuasselDatabase
 import de.kuschku.quasseldroid.util.helper.getOrPut
-import de.kuschku.quasseldroid.util.helper.visibleIf
 import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage
 import me.saket.bettermovementmethod.BetterLinkMovementMethod
 
@@ -150,10 +149,6 @@ class MessageAdapter(
     @JvmField
     var combined: TextView? = null
 
-    @BindView(R.id.markerline)
-    @JvmField
-    var markerline: View? = null
-
     private var message: FormattedMessage? = null
     private var selectable: Boolean = false
     private var clickable: Boolean = false
@@ -195,7 +190,6 @@ class MessageAdapter(
       name?.text = message.name
       content?.text = message.content
       combined?.text = message.combined
-      markerline?.visibleIf(message.isMarkerLine)
 
       this.itemView.isSelected = message.isSelected
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
index 22d11cf69..0d9a20d67 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt
@@ -377,6 +377,9 @@ class MessageListFragment : ServiceBoundFragment() {
 
     messageList.addOnScrollListener(preloader)
     messageList.addItemDecoration(DayChangeItemDecoration(adapter))
+    messageList.addItemDecoration(MarkerLineItemDecoration(
+      adapter, requireContext(), R.dimen.markerline_height, R.attr.colorMarkerLine
+    ))
 
     return view
   }
diff --git a/app/src/main/res/layout/widget_chatmessage_action.xml b/app/src/main/res/layout/widget_chatmessage_action.xml
index 80eeab9e0..357b871db 100644
--- a/app/src/main/res/layout/widget_chatmessage_action.xml
+++ b/app/src/main/res/layout/widget_chatmessage_action.xml
@@ -4,67 +4,54 @@
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/backgroundMenuItem"
-  android:orientation="vertical"
+  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">
 
-  <LinearLayout
-    android:layout_width="match_parent"
+  <TextView
+    android:id="@+id/time_left"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    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:layout_gravity="top"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:typeface="monospace"
+    tools:text="@sample/messages.json/data/time" />
 
-    <TextView
-      android:id="@+id/time_left"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:typeface="monospace"
-      tools:text="@sample/messages.json/data/time" />
-
-    <Space
-      android:id="@+id/avatar_placeholder"
-      android:layout_width="@dimen/avatar_size"
-      android:layout_height="match_parent"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:visibility="gone" />
-
-    <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
-      android:id="@+id/combined"
-      android:layout_width="0dip"
-      android:layout_height="wrap_content"
-      android:layout_weight="1"
-      android:textColor="?attr/colorForegroundAction"
-      android:textStyle="italic"
-      tools:text="@sample/messages.json/data/message" />
+  <Space
+    android:id="@+id/avatar_placeholder"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="match_parent"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:visibility="gone" />
 
-    <TextView
-      android:id="@+id/time_right"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top"
-      android:layout_marginLeft="@dimen/message_horizontal"
-      android:layout_marginStart="@dimen/message_horizontal"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:textStyle="italic"
-      android:visibility="gone"
-      tools:text="@sample/messages.json/data/time"
-      tools:textSize="11.9sp"
-      tools:visibility="visible" />
-  </LinearLayout>
+  <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
+    android:id="@+id/combined"
+    android:layout_width="0dip"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:textColor="?attr/colorForegroundAction"
+    android:textStyle="italic"
+    tools:text="@sample/messages.json/data/message" />
 
-  <View
-    android:id="@+id/markerline"
-    android:layout_width="match_parent"
-    android:layout_height="1dp"
-    android:background="?colorMarkerLine"
-    android:visibility="gone" />
-</LinearLayout>
\ No newline at end of file
+  <TextView
+    android:id="@+id/time_right"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top"
+    android:layout_marginLeft="@dimen/message_horizontal"
+    android:layout_marginStart="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:textStyle="italic"
+    android:visibility="gone"
+    tools:text="@sample/messages.json/data/time"
+    tools:textSize="11.9sp"
+    tools:visibility="visible" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_daychange.xml b/app/src/main/res/layout/widget_chatmessage_daychange.xml
index eda4795f9..a8a5bee40 100644
--- a/app/src/main/res/layout/widget_chatmessage_daychange.xml
+++ b/app/src/main/res/layout/widget_chatmessage_daychange.xml
@@ -7,10 +7,6 @@
   android:orientation="vertical"
   android:textAppearance="?android:attr/textAppearanceListItemSmall">
 
-  <Space
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/message_vertical" />
-
   <View
     android:layout_width="match_parent"
     android:layout_height="1dp"
diff --git a/app/src/main/res/layout/widget_chatmessage_error.xml b/app/src/main/res/layout/widget_chatmessage_error.xml
index e543bb3f7..3e6cc388d 100644
--- a/app/src/main/res/layout/widget_chatmessage_error.xml
+++ b/app/src/main/res/layout/widget_chatmessage_error.xml
@@ -4,65 +4,52 @@
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/backgroundMenuItem"
-  android:orientation="vertical"
+  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">
 
-  <LinearLayout
-    android:layout_width="match_parent"
+  <TextView
+    android:id="@+id/time_left"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    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:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:typeface="monospace"
+    tools:text="@sample/messages.json/data/time" />
 
-    <TextView
-      android:id="@+id/time_left"
-      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"
-      tools:text="@sample/messages.json/data/time" />
-
-    <Space
-      android:id="@+id/avatar_placeholder"
-      android:layout_width="@dimen/avatar_size"
-      android:layout_height="match_parent"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:visibility="gone" />
-
-    <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
-      android:id="@+id/combined"
-      android:layout_width="0dip"
-      android:layout_height="wrap_content"
-      android:layout_weight="1"
-      android:textColor="?attr/colorForegroundError"
-      tools:text="@sample/messages.json/data/message" />
+  <Space
+    android:id="@+id/avatar_placeholder"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="match_parent"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:visibility="gone" />
 
-    <TextView
-      android:id="@+id/time_right"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top"
-      android:layout_marginLeft="@dimen/message_horizontal"
-      android:layout_marginStart="@dimen/message_horizontal"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:textStyle="italic"
-      android:visibility="gone"
-      tools:text="@sample/messages.json/data/time"
-      tools:textSize="11.9sp"
-      tools:visibility="visible" />
-  </LinearLayout>
+  <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
+    android:id="@+id/combined"
+    android:layout_width="0dip"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:textColor="?attr/colorForegroundError"
+    tools:text="@sample/messages.json/data/message" />
 
-  <View
-    android:id="@+id/markerline"
-    android:layout_width="match_parent"
-    android:layout_height="1dp"
-    android:background="?colorMarkerLine"
-    android:visibility="gone" />
-</LinearLayout>
\ No newline at end of file
+  <TextView
+    android:id="@+id/time_right"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top"
+    android:layout_marginLeft="@dimen/message_horizontal"
+    android:layout_marginStart="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:textStyle="italic"
+    android:visibility="gone"
+    tools:text="@sample/messages.json/data/time"
+    tools:textSize="11.9sp"
+    tools:visibility="visible" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_info.xml b/app/src/main/res/layout/widget_chatmessage_info.xml
index 9deb77d4d..8b304e287 100644
--- a/app/src/main/res/layout/widget_chatmessage_info.xml
+++ b/app/src/main/res/layout/widget_chatmessage_info.xml
@@ -4,66 +4,53 @@
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/backgroundMenuItem"
-  android:orientation="vertical"
+  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">
 
-  <LinearLayout
-    android:layout_width="match_parent"
+  <TextView
+    android:id="@+id/time_left"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    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:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:fontFamily="monospace"
+    android:textColor="?attr/colorForegroundSecondary"
+    tools:text="@sample/messages.json/data/time" />
 
-    <TextView
-      android:id="@+id/time_left"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:fontFamily="monospace"
-      android:textColor="?attr/colorForegroundSecondary"
-      tools:text="@sample/messages.json/data/time" />
-
-    <Space
-      android:id="@+id/avatar_placeholder"
-      android:layout_width="@dimen/avatar_size"
-      android:layout_height="match_parent"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:visibility="gone" />
-
-    <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
-      android:id="@+id/combined"
-      android:layout_width="0dip"
-      android:layout_height="wrap_content"
-      android:layout_weight="1"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:textStyle="italic"
-      tools:text="@sample/messages.json/data/message" />
+  <Space
+    android:id="@+id/avatar_placeholder"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="match_parent"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:visibility="gone" />
 
-    <TextView
-      android:id="@+id/time_right"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top"
-      android:layout_marginLeft="@dimen/message_horizontal"
-      android:layout_marginStart="@dimen/message_horizontal"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:textStyle="italic"
-      android:visibility="gone"
-      tools:text="@sample/messages.json/data/time"
-      tools:textSize="11.9sp"
-      tools:visibility="visible" />
-  </LinearLayout>
+  <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
+    android:id="@+id/combined"
+    android:layout_width="0dip"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:textStyle="italic"
+    tools:text="@sample/messages.json/data/message" />
 
-  <View
-    android:id="@+id/markerline"
-    android:layout_width="match_parent"
-    android:layout_height="1dp"
-    android:background="?colorMarkerLine"
-    android:visibility="gone" />
-</LinearLayout>
\ No newline at end of file
+  <TextView
+    android:id="@+id/time_right"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top"
+    android:layout_marginLeft="@dimen/message_horizontal"
+    android:layout_marginStart="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:textStyle="italic"
+    android:visibility="gone"
+    tools:text="@sample/messages.json/data/time"
+    tools:textSize="11.9sp"
+    tools:visibility="visible" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_notice.xml b/app/src/main/res/layout/widget_chatmessage_notice.xml
index a03184b1c..5b18d8d84 100644
--- a/app/src/main/res/layout/widget_chatmessage_notice.xml
+++ b/app/src/main/res/layout/widget_chatmessage_notice.xml
@@ -4,65 +4,52 @@
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/backgroundMenuItem"
-  android:orientation="vertical"
+  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">
 
-  <LinearLayout
-    android:layout_width="match_parent"
+  <TextView
+    android:id="@+id/time_left"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    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:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:fontFamily="monospace"
+    android:textColor="?attr/colorForegroundNotice"
+    tools:text="@sample/messages.json/data/time" />
 
-    <TextView
-      android:id="@+id/time_left"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:fontFamily="monospace"
-      android:textColor="?attr/colorForegroundNotice"
-      tools:text="@sample/messages.json/data/time" />
-
-    <Space
-      android:id="@+id/avatar_placeholder"
-      android:layout_width="@dimen/avatar_size"
-      android:layout_height="match_parent"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:visibility="gone" />
-
-    <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
-      android:id="@+id/combined"
-      android:layout_width="0dip"
-      android:layout_height="wrap_content"
-      android:layout_weight="1"
-      android:textColor="?attr/colorForegroundNotice"
-      tools:text="@sample/messages.json/data/message" />
+  <Space
+    android:id="@+id/avatar_placeholder"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="match_parent"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:visibility="gone" />
 
-    <TextView
-      android:id="@+id/time_right"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top"
-      android:layout_marginLeft="@dimen/message_horizontal"
-      android:layout_marginStart="@dimen/message_horizontal"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:textStyle="italic"
-      android:visibility="gone"
-      tools:text="@sample/messages.json/data/time"
-      tools:textSize="11.9sp"
-      tools:visibility="visible" />
-  </LinearLayout>
+  <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
+    android:id="@+id/combined"
+    android:layout_width="0dip"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:textColor="?attr/colorForegroundNotice"
+    tools:text="@sample/messages.json/data/message" />
 
-  <View
-    android:id="@+id/markerline"
-    android:layout_width="match_parent"
-    android:layout_height="1dp"
-    android:background="?colorMarkerLine"
-    android:visibility="gone" />
-</LinearLayout>
\ No newline at end of file
+  <TextView
+    android:id="@+id/time_right"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top"
+    android:layout_marginLeft="@dimen/message_horizontal"
+    android:layout_marginStart="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:textStyle="italic"
+    android:visibility="gone"
+    tools:text="@sample/messages.json/data/time"
+    tools:textSize="11.9sp"
+    tools:visibility="visible" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_plain.xml b/app/src/main/res/layout/widget_chatmessage_plain.xml
index 85bf7eeb2..03709e314 100644
--- a/app/src/main/res/layout/widget_chatmessage_plain.xml
+++ b/app/src/main/res/layout/widget_chatmessage_plain.xml
@@ -4,120 +4,107 @@
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/backgroundMenuItem"
-  android:orientation="vertical"
+  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"
   tools:showIn="@layout/fragment_messages">
 
+  <TextView
+    android:id="@+id/time_left"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:typeface="monospace"
+    tools:text="@sample/messages.json/data/time"
+    tools:visibility="gone" />
+
+  <FrameLayout
+    android:id="@+id/avatar_container"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="wrap_content"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:visibility="gone"
+    tools:visibility="visible">
+
+    <ImageView
+      android:id="@+id/avatar"
+      android:layout_width="@dimen/avatar_size"
+      android:layout_height="@dimen/avatar_size"
+      android:contentDescription="@string/label_avatar"
+      android:visibility="gone"
+      tools:src="@tools:sample/avatars"
+      tools:visibility="visible" />
+  </FrameLayout>
+
   <LinearLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    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:layout_gravity="fill_vertical"
+    android:orientation="vertical">
 
     <TextView
-      android:id="@+id/time_left"
+      android:id="@+id/name"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
-      android:layout_gravity="top"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
+      android:layout_gravity="center_vertical"
       android:textColor="?attr/colorForegroundSecondary"
-      android:typeface="monospace"
-      tools:text="@sample/messages.json/data/time"
-      tools:visibility="gone" />
-
-    <FrameLayout
-      android:id="@+id/avatar_container"
-      android:layout_width="@dimen/avatar_size"
-      android:layout_height="wrap_content"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
       android:visibility="gone"
-      tools:visibility="visible">
-
-      <ImageView
-        android:id="@+id/avatar"
-        android:layout_width="@dimen/avatar_size"
-        android:layout_height="@dimen/avatar_size"
-        android:contentDescription="@string/label_avatar"
-        android:visibility="gone"
-        tools:src="@tools:sample/avatars"
-        tools:visibility="visible" />
-    </FrameLayout>
+      tools:text="@sample/messages.json/data/sender"
+      tools:visibility="visible" />
 
     <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:layout_gravity="fill_vertical"
-      android:orientation="vertical">
-
-      <TextView
-        android:id="@+id/name"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:textColor="?attr/colorForegroundSecondary"
-        android:visibility="gone"
-        tools:text="@sample/messages.json/data/sender"
-        tools:visibility="visible" />
+      android:layout_gravity="center_vertical|fill_horizontal"
+      android:orientation="horizontal">
 
       <LinearLayout
-        android:layout_width="match_parent"
+        android:layout_width="0dip"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical|fill_horizontal"
-        android:orientation="horizontal">
+        android:layout_weight="1"
+        android:orientation="vertical">
 
-        <LinearLayout
-          android:layout_width="0dip"
+        <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
+          android:id="@+id/content"
+          android:layout_width="match_parent"
           android:layout_height="wrap_content"
-          android:layout_weight="1"
-          android:orientation="vertical">
-
-          <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
-            android:id="@+id/content"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textColor="?attr/colorForeground"
-            android:visibility="gone"
-            tools:text="@sample/messages.json/data/content"
-            tools:visibility="visible" />
-
-          <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
-            android:id="@+id/combined"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textColor="?attr/colorForeground"
-            tools:text="@sample/messages.json/data/message"
-            tools:visibility="gone" />
-
-        </LinearLayout>
-
-        <TextView
-          android:id="@+id/time_right"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:layout_gravity="top"
-          android:layout_marginLeft="@dimen/message_horizontal"
-          android:layout_marginStart="@dimen/message_horizontal"
-          android:textColor="?attr/colorForegroundSecondary"
-          android:textStyle="italic"
+          android:textColor="?attr/colorForeground"
           android:visibility="gone"
-          tools:text="@sample/messages.json/data/time"
-          tools:textSize="11.9sp"
+          tools:text="@sample/messages.json/data/content"
           tools:visibility="visible" />
+
+        <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
+          android:id="@+id/combined"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:textColor="?attr/colorForeground"
+          tools:text="@sample/messages.json/data/message"
+          tools:visibility="gone" />
+
       </LinearLayout>
+
+      <TextView
+        android:id="@+id/time_right"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:layout_marginLeft="@dimen/message_horizontal"
+        android:layout_marginStart="@dimen/message_horizontal"
+        android:textColor="?attr/colorForegroundSecondary"
+        android:textStyle="italic"
+        android:visibility="gone"
+        tools:text="@sample/messages.json/data/time"
+        tools:textSize="11.9sp"
+        tools:visibility="visible" />
     </LinearLayout>
   </LinearLayout>
-
-  <View
-    android:id="@+id/markerline"
-    android:layout_width="match_parent"
-    android:layout_height="1dp"
-    android:background="?colorMarkerLine"
-    android:visibility="gone" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage_server.xml b/app/src/main/res/layout/widget_chatmessage_server.xml
index 4b27c76ed..0981257a5 100644
--- a/app/src/main/res/layout/widget_chatmessage_server.xml
+++ b/app/src/main/res/layout/widget_chatmessage_server.xml
@@ -4,65 +4,52 @@
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/backgroundMenuItem"
-  android:orientation="vertical"
+  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">
 
-  <LinearLayout
-    android:layout_width="match_parent"
+  <TextView
+    android:id="@+id/time_left"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    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:layout_marginLeft="@dimen/message_horizontal"
+    android:layout_marginStart="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:typeface="monospace"
+    tools:text="@sample/messages.json/data/time" />
 
-    <TextView
-      android:id="@+id/time_left"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginLeft="@dimen/message_horizontal"
-      android:layout_marginStart="@dimen/message_horizontal"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:typeface="monospace"
-      tools:text="@sample/messages.json/data/time" />
-
-    <Space
-      android:id="@+id/avatar_placeholder"
-      android:layout_width="@dimen/avatar_size"
-      android:layout_height="match_parent"
-      android:layout_marginEnd="@dimen/message_horizontal"
-      android:layout_marginRight="@dimen/message_horizontal"
-      android:visibility="gone" />
-
-    <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
-      android:id="@+id/combined"
-      android:layout_width="0dip"
-      android:layout_height="wrap_content"
-      android:layout_weight="1"
-      android:textColor="?attr/colorForegroundSecondary"
-      tools:text="@sample/messages.json/data/message" />
+  <Space
+    android:id="@+id/avatar_placeholder"
+    android:layout_width="@dimen/avatar_size"
+    android:layout_height="match_parent"
+    android:layout_marginEnd="@dimen/message_horizontal"
+    android:layout_marginRight="@dimen/message_horizontal"
+    android:visibility="gone" />
 
-    <TextView
-      android:id="@+id/time_right"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="top"
-      android:layout_marginLeft="@dimen/message_horizontal"
-      android:layout_marginStart="@dimen/message_horizontal"
-      android:textColor="?attr/colorForegroundSecondary"
-      android:textStyle="italic"
-      android:visibility="gone"
-      tools:text="@sample/messages.json/data/time"
-      tools:textSize="11.9sp"
-      tools:visibility="visible" />
-  </LinearLayout>
+  <de.kuschku.quasseldroid.ui.chat.messages.RipplePassthroughTextView
+    android:id="@+id/combined"
+    android:layout_width="0dip"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:textColor="?attr/colorForegroundSecondary"
+    tools:text="@sample/messages.json/data/message" />
 
-  <View
-    android:id="@+id/markerline"
-    android:layout_width="match_parent"
-    android:layout_height="1dp"
-    android:background="?colorMarkerLine"
-    android:visibility="gone" />
-</LinearLayout>
\ No newline at end of file
+  <TextView
+    android:id="@+id/time_right"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top"
+    android:layout_marginLeft="@dimen/message_horizontal"
+    android:layout_marginStart="@dimen/message_horizontal"
+    android:textColor="?attr/colorForegroundSecondary"
+    android:textStyle="italic"
+    android:visibility="gone"
+    tools:text="@sample/messages.json/data/time"
+    tools:textSize="11.9sp"
+    tools:visibility="visible" />
+</LinearLayout>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index cf895323a..c185448bb 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -5,6 +5,8 @@
   <dimen name="message_vertical">2dp</dimen>
   <dimen name="message_vertical_daychange">8dp</dimen>
 
+  <dimen name="markerline_height">1dp</dimen>
+
   <dimen name="autocomplete_max_height">96dp</dimen>
 
   <dimen name="max_content_width">480dp</dimen>
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index 07001df1e..b9e0fea61 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -3,4 +3,6 @@
   <item name="tag_daychange" type="id" />
   <item name="tag_daychange_layout" type="id" />
   <item name="tag_daychange_content" type="id" />
+
+  <item name="tag_markerline" type="id" />
 </resources>
-- 
GitLab