From d70e585bacdf54fcca951d898647e443bd6163e9 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sun, 28 Aug 2016 19:34:56 +0200
Subject: [PATCH] Improved performance

---
 .../syncables/types/impl/IrcChannel.java      |  4 +
 .../syncables/types/impl/Network.java         |  5 +
 .../ui/chat/chatview/ChatMessageRenderer.java | 93 ++++++-------------
 .../ui/chat/chatview/MessageAdapter.java      | 15 ++-
 .../ui/chat/chatview/MessageViewHolder.java   |  9 +-
 .../res/layout/widget_chatmessage_action.xml  | 55 +++++++++++
 .../res/layout/widget_chatmessage_error.xml   | 56 +++++++++++
 ...ssage.xml => widget_chatmessage_plain.xml} |  9 +-
 .../res/layout/widget_chatmessage_server.xml  | 56 +++++++++++
 9 files changed, 234 insertions(+), 68 deletions(-)
 create mode 100644 app/src/main/res/layout/widget_chatmessage_action.xml
 create mode 100644 app/src/main/res/layout/widget_chatmessage_error.xml
 rename app/src/main/res/layout/{widget_chatmessage.xml => widget_chatmessage_plain.xml} (88%)
 create mode 100644 app/src/main/res/layout/widget_chatmessage_server.xml

diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java
index d8aaa270e..06b92474c 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java
@@ -261,6 +261,7 @@ public class IrcChannel extends AIrcChannel<IrcChannel> {
     public void _setTopic(String topic) {
         this.topic = topic;
         _update();
+        updateDisplay();
     }
 
     @Override
@@ -532,6 +533,9 @@ public class IrcChannel extends AIrcChannel<IrcChannel> {
     @Override
     public void _update() {
         super._update();
+    }
+
+    private void updateDisplay() {
         if (client.connectionStatus() != ConnectionChangeEvent.Status.INITIALIZING_DATA) {
             ChannelBuffer buffer = client.bufferManager().channel(this);
             if (buffer != null) {
diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java
index a5e33688b..9e3161c36 100644
--- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java
+++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/Network.java
@@ -529,6 +529,7 @@ public class Network extends ANetwork<Network> implements Observer {
     public void _setConnected(boolean isConnected) {
         this.isConnected = isConnected;
         _update();
+        updateDisplay();
     }
 
     @Override
@@ -723,6 +724,7 @@ public class Network extends ANetwork<Network> implements Observer {
         if (this.networkInfo != null)
             this.networkInfo.addObserver(this);
         _update();
+        updateDisplay();
     }
 
     @Override
@@ -779,6 +781,9 @@ public class Network extends ANetwork<Network> implements Observer {
     @Override
     public void _update() {
         super._update();
+    }
+
+    private void updateDisplay() {
         if (client != null && client.connectionStatus() != ConnectionChangeEvent.Status.INITIALIZING_DATA && client.bufferViewManager() != null) {
             StatusBuffer buffer = client.bufferManager().network(networkInfo.networkId());
             if (buffer != null) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java
index 349984701..0f345f9e1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/ChatMessageRenderer.java
@@ -21,13 +21,14 @@
 
 package de.kuschku.quasseldroid_ng.ui.chat.chatview;
 
-import android.graphics.Typeface;
 import android.support.annotation.ColorInt;
+import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.UiThread;
 
 import de.kuschku.libquassel.localtypes.buffers.Buffer;
 import de.kuschku.libquassel.message.Message;
+import de.kuschku.quasseldroid_ng.R;
 import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
 import de.kuschku.util.irc.IrcUserUtils;
 import de.kuschku.util.irc.format.IrcFormatHelper;
@@ -40,11 +41,6 @@ public class ChatMessageRenderer {
     @NonNull
     private final AppContext context;
     private IrcFormatHelper helper;
-    private MessageStyleContainer highlightStyle;
-    private MessageStyleContainer serverStyle;
-    private MessageStyleContainer errorStyle;
-    private MessageStyleContainer actionStyle;
-    private MessageStyleContainer plainStyle;
 
     public ChatMessageRenderer(@NonNull AppContext context) {
         this.context = context;
@@ -53,45 +49,6 @@ public class ChatMessageRenderer {
 
     public void setTheme(@NonNull AppContext context) {
         this.helper = new IrcFormatHelper(context);
-
-        this.highlightStyle = new MessageStyleContainer(
-                context.themeUtil().res.colorForegroundHighlight,
-                Typeface.NORMAL,
-                context.themeUtil().res.colorForegroundHighlight,
-                context.themeUtil().res.colorBackgroundHighlight
-        );
-        this.serverStyle = new MessageStyleContainer(
-                context.themeUtil().res.colorForegroundSecondary,
-                Typeface.ITALIC,
-                context.themeUtil().res.colorForegroundSecondary,
-                context.themeUtil().res.colorBackgroundSecondary
-        );
-        this.errorStyle = new MessageStyleContainer(
-                context.themeUtil().res.colorForegroundError,
-                Typeface.ITALIC,
-                context.themeUtil().res.colorForegroundSecondary,
-                context.themeUtil().res.colorBackgroundSecondary
-        );
-        this.plainStyle = new MessageStyleContainer(
-                context.themeUtil().res.colorForeground,
-                Typeface.NORMAL,
-                context.themeUtil().res.colorForegroundSecondary,
-                context.themeUtil().res.transparent
-        );
-        this.actionStyle = new MessageStyleContainer(
-                context.themeUtil().res.colorForegroundAction,
-                Typeface.ITALIC,
-                context.themeUtil().res.colorForegroundSecondary,
-                context.themeUtil().res.transparent
-        );
-    }
-
-    private void applyStyle(@NonNull MessageViewHolder holder, @NonNull MessageStyleContainer style, @NonNull MessageStyleContainer highlightStyle, boolean highlight) {
-        MessageStyleContainer container = highlight ? highlightStyle : style;
-        holder.content.setTextColor(container.textColor);
-        holder.content.setTypeface(null, container.fontstyle);
-        holder.time.setTextColor(container.timeColor);
-        holder.itemView.setBackgroundColor(container.bgColor);
     }
 
     @NonNull
@@ -120,7 +77,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindPlain(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, plainStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(
                 context.themeUtil().translations.formatPlain(
                         formatNick(message.sender, false),
@@ -130,7 +86,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindNotice(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(context.themeUtil().translations.formatAction(
                 formatNick(message.sender, false),
                 helper.formatIrcMessage(context.client(), message)
@@ -138,7 +93,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindAction(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, actionStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(
                 context.themeUtil().translations.formatAction(
                         formatNick(message.sender, false),
@@ -148,7 +102,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindNick(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         // FIXME: Ugly hack to get around the issue that quasselcore doesn’t set the Self flag
         boolean self = message.flags.Self || message.sender.equals(message.content);
         if (self)
@@ -164,7 +117,6 @@ public class ChatMessageRenderer {
 
     // TODO: Replace this with better display of mode changes
     private void onBindMode(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(context.themeUtil().translations.formatMode(
                 message.content,
                 formatNick(message.sender, false)
@@ -172,7 +124,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindJoin(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(context.themeUtil().translations.formatJoin(
                 formatNick(message.sender),
                 getBufferName(message)
@@ -180,7 +131,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindPart(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(context.themeUtil().translations.formatPart(
                 formatNick(message.sender),
                 getBufferName(message),
@@ -189,7 +139,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindQuit(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         if (message.content == null || message.content.isEmpty())
             holder.content.setText(context.themeUtil().translations.formatQuit(
                     formatNick(message.sender)
@@ -202,7 +151,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindKick(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         if (message.content.contains(" "))
             holder.content.setText(context.themeUtil().translations.formatKick(
                     formatNick(message.sender),
@@ -219,7 +167,6 @@ public class ChatMessageRenderer {
     }
 
     private void onBindKill(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         if (message.content.contains(" "))
             holder.content.setText(context.themeUtil().translations.formatKill(
                     formatNick(message.sender),
@@ -234,44 +181,36 @@ public class ChatMessageRenderer {
     }
 
     private void onBindServer(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(message.content);
     }
 
     private void onBindInfo(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(message.content);
     }
 
     private void onBindError(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, errorStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(message.content);
     }
 
     private void onBindDayChange(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(context.themeUtil().translations.formatDayChange(
                 context.themeUtil().formatter.getLongDateFormatter().print(message.time)
         ));
     }
 
     private void onBindTopic(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(message.content);
     }
 
     private void onBindNetsplitJoin(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(message.toString());
     }
 
     private void onBindNetsplitQuit(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(message.toString());
     }
 
     private void onBindInvite(@NonNull MessageViewHolder holder, @NonNull Message message) {
-        applyStyle(holder, serverStyle, highlightStyle, message.flags.Highlight);
         holder.content.setText(message.toString());
     }
 
@@ -354,4 +293,32 @@ public class ChatMessageRenderer {
             this.bgColor = bgColor;
         }
     }
+
+    public @LayoutRes int getLayoutRes(Message.Type type) {
+        switch (type) {
+            default:
+            case Plain:
+                return R.layout.widget_chatmessage_plain;
+            case Action:
+                return R.layout.widget_chatmessage_action;
+            case Nick:
+            case Notice:
+            case Mode:
+            case Join:
+            case Part:
+            case Quit:
+            case Kick:
+            case Kill:
+            case Server:
+            case Info:
+            case DayChange:
+            case Topic:
+            case NetsplitJoin:
+            case NetsplitQuit:
+            case Invite:
+                return R.layout.widget_chatmessage_server;
+            case Error:
+                return R.layout.widget_chatmessage_error;
+        }
+    }
 }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageAdapter.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageAdapter.java
index fd7ecb4b8..fd767b28b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageAdapter.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageAdapter.java
@@ -53,8 +53,11 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> {
     private final UICallback callback;
     @NonNull
     private IObservableList<UICallback, Message> messageList = emptyList();
+    @NonNull
+    private AppContext context;
 
     public MessageAdapter(@NonNull Context ctx, @NonNull AppContext context, @Nullable AutoScroller scroller) {
+        this.context = context;
         this.inflater = LayoutInflater.from(ctx);
         this.renderer = new ChatMessageRenderer(context);
         this.callback = new AdapterUICallbackWrapper(this, scroller);
@@ -75,7 +78,9 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> {
     @NonNull
     @Override
     public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        return new MessageViewHolder(inflater.inflate(R.layout.widget_chatmessage, parent, false));
+        boolean highlightFlag = viewType % 2 == 1;
+        Message.Type actualType = Message.Type.fromId(viewType >> 1);
+        return new MessageViewHolder(context, inflater.inflate(renderer.getLayoutRes(actualType), parent, false), highlightFlag);
     }
 
     @Override
@@ -86,6 +91,14 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> {
         renderer.onBind(holder, msg);
     }
 
+    @Override
+    public int getItemViewType(int position) {
+        Message message = getItem(position);
+        Message.Type type = message.type;
+        int highlightFlag = message.flags.Highlight ? 1 : 0;
+        return type.value << 1 | highlightFlag;
+    }
+
     @Override
     public int getItemCount() {
         return messageList.size();
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageViewHolder.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageViewHolder.java
index 5c8f238de..869b8858e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageViewHolder.java
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/chatview/MessageViewHolder.java
@@ -31,6 +31,7 @@ import android.widget.TextView;
 import butterknife.Bind;
 import butterknife.ButterKnife;
 import de.kuschku.quasseldroid_ng.R;
+import de.kuschku.quasseldroid_ng.ui.theme.AppContext;
 
 @UiThread
 public class MessageViewHolder extends RecyclerView.ViewHolder {
@@ -44,9 +45,15 @@ public class MessageViewHolder extends RecyclerView.ViewHolder {
     @Bind(R.id.content)
     TextView content;
 
-    public MessageViewHolder(@NonNull View itemView) {
+    public MessageViewHolder(@NonNull AppContext context, @NonNull View itemView, boolean highlightFlag) {
         super(itemView);
         ButterKnife.bind(this, itemView);
         content.setMovementMethod(LinkMovementMethod.getInstance());
+
+        if (highlightFlag) {
+            itemView.setBackgroundColor(context.themeUtil().res.colorBackgroundHighlight);
+            content.setTextColor(context.themeUtil().res.colorForegroundHighlight);
+            time.setTextColor(context.themeUtil().res.colorForegroundHighlight);
+        }
     }
 }
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..f76132db7
--- /dev/null
+++ b/app/src/main/res/layout/widget_chatmessage_action.xml
@@ -0,0 +1,55 @@
+<?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: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:clickable="true"
+        android:textColor="?attr/colorForegroundAction"
+        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..aacd2bc0e
--- /dev/null
+++ b/app/src/main/res/layout/widget_chatmessage_error.xml
@@ -0,0 +1,56 @@
+<?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:background="?attr/colorBackgroundSecondary"
+    android:clickable="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:clickable="true"
+        android:textColor="?attr/colorForegroundError"
+        android:textStyle="italic"/>
+</LinearLayout>
diff --git a/app/src/main/res/layout/widget_chatmessage.xml b/app/src/main/res/layout/widget_chatmessage_plain.xml
similarity index 88%
rename from app/src/main/res/layout/widget_chatmessage.xml
rename to app/src/main/res/layout/widget_chatmessage_plain.xml
index 021b53088..930caad64 100644
--- a/app/src/main/res/layout/widget_chatmessage.xml
+++ b/app/src/main/res/layout/widget_chatmessage_plain.xml
@@ -20,7 +20,8 @@
   ~ with this program.  If not, see <http://www.gnu.org/licenses/>.
   -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:clickable="true"
@@ -40,12 +41,14 @@
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/message_horizontal"
         android:layout_marginRight="@dimen/message_horizontal"
-        android:typeface="monospace" />
+        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:clickable="true" />
+        android:clickable="true"
+        android:textColor="?attr/colorForeground"/>
 </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..8255e3513
--- /dev/null
+++ b/app/src/main/res/layout/widget_chatmessage_server.xml
@@ -0,0 +1,56 @@
+<?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:background="?attr/colorBackgroundSecondary"
+    android:clickable="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:clickable="true"
+        android:textColor="?attr/colorForegroundSecondary"
+        android:textStyle="italic"/>
+</LinearLayout>
-- 
GitLab