Browse Source

Some progress on replies

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic 5 years ago
parent
commit
2613c1f074

+ 2 - 2
app/build.gradle

@@ -39,8 +39,8 @@ android {
         targetSdkVersion 28
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 
-        versionCode 122
-        versionName "7.0.8"
+        versionCode 115
+        versionName "8"
 
         flavorDimensions "default"
         renderscriptTargetApi 19

+ 0 - 206
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.java

@@ -1,206 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * 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/>.
- */
-
-package com.nextcloud.talk.adapters.messages;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.net.Uri;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.TextUtils;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.TextView;
-import androidx.core.view.ViewCompat;
-import androidx.emoji.widget.EmojiTextView;
-
-import autodagger.AutoInjector;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.amulyakhare.textdrawable.TextDrawable;
-import com.facebook.drawee.view.SimpleDraweeView;
-import com.google.android.flexbox.FlexboxLayout;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.models.json.chat.ChatMessage;
-import com.nextcloud.talk.utils.DisplayUtils;
-import com.nextcloud.talk.utils.TextMatchers;
-import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.nextcloud.talk.utils.preferences.AppPreferences;
-import com.stfalcon.chatkit.messages.MessageHolders;
-import com.vanniktech.emoji.emoji.Emoji;
-
-import javax.inject.Inject;
-import java.util.HashMap;
-import java.util.Map;
-
-@AutoInjector(NextcloudTalkApplication.class)
-public class MagicIncomingTextMessageViewHolder
-        extends MessageHolders.IncomingTextMessageViewHolder<ChatMessage> {
-
-    @BindView(R.id.messageAuthor)
-    EmojiTextView messageAuthor;
-
-    @BindView(R.id.messageText)
-    EmojiTextView messageText;
-
-    @BindView(R.id.messageUserAvatar)
-    SimpleDraweeView messageUserAvatarView;
-
-    @BindView(R.id.messageTime)
-    TextView messageTimeView;
-
-    @Inject
-    UserUtils userUtils;
-
-    @Inject
-    Context context;
-
-    @Inject
-    AppPreferences appPreferences;
-
-    private View itemView;
-
-    public MagicIncomingTextMessageViewHolder(View itemView) {
-        super(itemView);
-        ButterKnife.bind(this, itemView);
-        NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
-
-        this.itemView = itemView;
-    }
-
-
-    @Override
-    public void onBind(ChatMessage message) {
-        super.onBind(message);
-        String author;
-
-        if (!TextUtils.isEmpty(author = message.getActorDisplayName())) {
-            messageAuthor.setText(author);
-        } else {
-            messageAuthor.setText(R.string.nc_nick_guest);
-        }
-
-        if (!message.isGrouped() && !message.isOneToOneConversation()) {
-            messageUserAvatarView.setVisibility(View.VISIBLE);
-            if (message.getActorType().equals("guests")) {
-                // do nothing, avatar is set
-            } else if (message.getActorType().equals("bots") && message.getActorId().equals("changelog")) {
-                messageUserAvatarView.setController(null);
-                Drawable[] layers = new Drawable[2];
-                layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
-                layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
-                LayerDrawable layerDrawable = new LayerDrawable(layers);
-
-                messageUserAvatarView.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
-            } else if (message.getActorType().equals("bots")) {
-                messageUserAvatarView.setController(null);
-                TextDrawable drawable = TextDrawable.builder().beginConfig().bold().endConfig().buildRound(">",
-                                context.getResources().getColor(R.color.black));
-                messageUserAvatarView.setVisibility(View.VISIBLE);
-                messageUserAvatarView.getHierarchy().setPlaceholderImage(drawable);
-            }
-        } else {
-            if (message.isOneToOneConversation()) {
-                messageUserAvatarView.setVisibility(View.GONE);
-            } else {
-                messageUserAvatarView.setVisibility(View.INVISIBLE);
-            }
-            messageAuthor.setVisibility(View.GONE);
-        }
-
-        Resources resources = itemView.getResources();
-
-        int bg_bubble_color = resources.getColor(R.color.bg_message_list_incoming_bubble);
-
-        int bubbleResource = R.drawable.shape_incoming_message;
-
-        if (message.isGrouped) {
-            bubbleResource = R.drawable.shape_grouped_incoming_message;
-        }
-
-        Drawable bubbleDrawable = DisplayUtils.getMessageSelector(bg_bubble_color,
-                resources.getColor(R.color.transparent),
-                bg_bubble_color, bubbleResource);
-        ViewCompat.setBackground(bubble, bubbleDrawable);
-
-        HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
-
-        itemView.setSelected(false);
-        messageTimeView.setTextColor(context.getResources().getColor(R.color.warm_grey_four));
-
-        FlexboxLayout.LayoutParams layoutParams = (FlexboxLayout.LayoutParams) messageTimeView.getLayoutParams();
-        layoutParams.setWrapBefore(false);
-
-        Spannable messageString = new SpannableString(message.getText());
-
-        float textSize = context.getResources().getDimension(R.dimen.chat_text_size);
-
-        if (messageParameters != null && messageParameters.size() > 0) {
-            for (String key : messageParameters.keySet()) {
-                Map<String, String> individualHashMap = message.getMessageParameters().get(key);
-                if (individualHashMap != null) {
-                    if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
-                        if (individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
-                            messageString =
-                                    DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
-                                            messageString,
-                                            individualHashMap.get("id"),
-                                            individualHashMap.get("name"),
-                                            individualHashMap.get("type"),
-                                            userUtils.getUserById(message.getActiveUser().getUserId()),
-                                            R.xml.chip_you);
-                        } else {
-                            messageString =
-                                    DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
-                                            messageString,
-                                            individualHashMap.get("id"),
-                                            individualHashMap.get("name"),
-                                            individualHashMap.get("type"),
-                                            userUtils.getUserById(message.getActiveUser().getUserId()),
-                                            R.xml.chip_others);
-                        }
-
-                    } else if (individualHashMap.get("type").equals("file")) {
-                        itemView.setOnClickListener(v -> {
-                            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
-                            context.startActivity(browserIntent);
-                        });
-
-                    }
-                }
-            }
-
-        } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())) {
-            textSize = (float) (textSize * 2.5);
-            layoutParams.setWrapBefore(true);
-            itemView.setSelected(true);
-            messageAuthor.setVisibility(View.GONE);
-        }
-
-        messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-        messageTimeView.setLayoutParams(layoutParams);
-        messageText.setText(messageString);
-    }
-}

+ 252 - 0
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt

@@ -0,0 +1,252 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * 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/>.
+ */
+
+package com.nextcloud.talk.adapters.messages
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
+import android.net.Uri
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.TextUtils
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.RelativeLayout
+import android.widget.TextView
+import androidx.core.view.ViewCompat
+import androidx.emoji.widget.EmojiTextView
+import autodagger.AutoInjector
+import butterknife.BindView
+import butterknife.ButterKnife
+import com.amulyakhare.textdrawable.TextDrawable
+import com.facebook.drawee.view.SimpleDraweeView
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
+import com.nextcloud.talk.models.json.chat.ChatMessage
+import com.nextcloud.talk.utils.DisplayUtils
+import com.nextcloud.talk.utils.TextMatchers
+import com.nextcloud.talk.utils.preferences.AppPreferences
+import com.stfalcon.chatkit.messages.MessageHolders
+import com.stfalcon.chatkit.utils.DateFormatter
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
+.IncomingTextMessageViewHolder<ChatMessage>(incomingView) {
+
+    @JvmField
+    @BindView(R.id.messageAuthor)
+    var messageAuthor: EmojiTextView? = null
+
+    @JvmField
+    @BindView(R.id.messageText)
+    var messageText: EmojiTextView? = null
+
+    @JvmField
+    @BindView(R.id.messageUserAvatar)
+    var messageUserAvatarView: SimpleDraweeView? = null
+
+    @JvmField
+    @BindView(R.id.messageTime)
+    var messageTimeView: TextView? = null
+
+    @JvmField
+    @BindView(R.id.quotedChatMessageView)
+    var quotedChatMessageView: RelativeLayout? = null
+
+    @JvmField
+    @BindView(R.id.quotedUserAvatar)
+    var quotedUserAvatar: SimpleDraweeView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessageAuthor)
+    var quotedUserName: EmojiTextView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessageImage)
+    var quotedMessagePreview: SimpleDraweeView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessage)
+    var quotedMessage: EmojiTextView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessageTime)
+    var quotedMessageTime: TextView? = null
+
+    @JvmField
+    @BindView(R.id.quoteColoredView)
+    var quoteColoredView: View? = null
+
+    @JvmField
+    @Inject
+    var context: Context? = null
+
+    @JvmField
+    @Inject
+    var appPreferences: AppPreferences? = null
+
+    init {
+        ButterKnife.bind(
+                this,
+                itemView
+        )
+    }
+
+    override fun onBind(message: ChatMessage) {
+        super.onBind(message)
+        sharedApplication!!.componentApplication.inject(this)
+        val author: String = message.actorDisplayName
+        if (!TextUtils.isEmpty(author)) {
+            messageAuthor!!.text = author
+        } else {
+            messageAuthor!!.setText(R.string.nc_nick_guest)
+        }
+
+        if (!message.isGrouped && !message.isOneToOneConversation) {
+            messageUserAvatarView!!.visibility = View.VISIBLE
+            if (message.actorType == "guests") {
+                // do nothing, avatar is set
+            } else if (message.actorType == "bots" && message.actorId == "changelog") {
+                val layers = arrayOfNulls<Drawable>(2)
+                layers[0] = context?.getDrawable(R.drawable.ic_launcher_background)
+                layers[1] = context?.getDrawable(R.drawable.ic_launcher_foreground)
+                val layerDrawable = LayerDrawable(layers)
+                messageUserAvatarView?.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
+            } else if (message.actorType == "bots") {
+                val drawable = TextDrawable.builder()
+                        .beginConfig()
+                        .bold()
+                        .endConfig()
+                        .buildRound(
+                                ">",
+                                context!!.resources.getColor(R.color.black)
+                        )
+                messageUserAvatarView!!.visibility = View.VISIBLE
+                messageUserAvatarView?.setImageDrawable(drawable)
+            }
+        } else {
+            if (message.isOneToOneConversation) {
+                messageUserAvatarView!!.visibility = View.GONE
+            } else {
+                messageUserAvatarView!!.visibility = View.INVISIBLE
+            }
+            messageAuthor!!.visibility = View.GONE
+        }
+
+        val resources = itemView.resources
+
+        val bg_bubble_color = resources.getColor(R.color.bg_message_list_incoming_bubble)
+
+        var bubbleResource = R.drawable.shape_incoming_message
+
+        if (message.isGrouped) {
+            bubbleResource = R.drawable.shape_grouped_incoming_message
+        }
+
+        val bubbleDrawable = DisplayUtils.getMessageSelector(
+                bg_bubble_color,
+                resources.getColor(R.color.transparent),
+                bg_bubble_color, bubbleResource
+        )
+        ViewCompat.setBackground(bubble, bubbleDrawable)
+
+        val messageParameters = message.messageParameters
+
+        itemView.isSelected = false
+        messageTimeView!!.setTextColor(context?.resources!!.getColor(R.color.warm_grey_four))
+
+        var messageString: Spannable = SpannableString(message.text)
+
+        var textSize = context?.resources!!.getDimension(R.dimen.chat_text_size)
+
+        if (messageParameters != null && messageParameters.size > 0) {
+            for (key in messageParameters.keys) {
+                val individualHashMap = message.messageParameters[key]
+                if (individualHashMap != null) {
+                    if (individualHashMap["type"] == "user" || individualHashMap["type"] == "guest" || individualHashMap["type"] == "call") {
+                        if (individualHashMap["id"] == message.activeUser!!.userId) {
+                            messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
+                                    messageText!!.context,
+                                    messageString,
+                                    individualHashMap["id"]!!,
+                                    individualHashMap["name"]!!,
+                                    individualHashMap["type"]!!,
+                                    message.activeUser!!,
+                                    R.xml.chip_you
+                            )
+                        } else {
+                            messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
+                                    messageText!!.context,
+                                    messageString,
+                                    individualHashMap["id"]!!,
+                                    individualHashMap["name"]!!,
+                                    individualHashMap["type"]!!,
+                                    message.activeUser!!,
+                                    R.xml.chip_others
+                            )
+                        }
+                    } else if (individualHashMap["type"] == "file") {
+                        itemView.setOnClickListener { v ->
+                            val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
+                            context!!.startActivity(browserIntent)
+                        }
+                    }
+                }
+            }
+        } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
+            textSize = (textSize * 2.5).toFloat()
+            itemView.isSelected = true
+            messageAuthor!!.visibility = View.GONE
+        }
+
+        messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
+        messageText!!.text = messageString
+
+        // parent message handling
+
+        message.parentMessage?.let { parentChatMessage ->
+            parentChatMessage.activeUser = message.activeUser
+            imageLoader.loadImage(quotedUserAvatar!!, parentChatMessage.user.avatar, null)
+            parentChatMessage.imageUrl?.let{
+                quotedMessagePreview?.visibility = View.VISIBLE
+                imageLoader.loadImage(quotedMessagePreview, it, null)
+            } ?: run {
+                quotedMessagePreview?.visibility = View.GONE
+            }
+            quotedUserName?.text = parentChatMessage.actorDisplayName
+                    ?: context!!.getText(R.string.nc_nick_guest)
+            quotedMessage?.text = parentChatMessage.text
+
+            quotedUserName?.setTextColor(context!!.resources.getColor(R.color.colorPrimary))
+
+            quotedMessageTime?.text = DateFormatter.format(parentChatMessage.createdAt, DateFormatter.Template.TIME)
+            quotedMessageTime?.setTextColor(context!!.resources.getColor(R.color.warm_grey_four))
+            quoteColoredView?.setBackgroundResource(R.color.colorPrimary)
+            quotedChatMessageView?.visibility = View.VISIBLE
+        } ?: run {
+            quotedChatMessageView?.visibility = View.GONE
+        }
+    }
+}

+ 0 - 140
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java

@@ -1,140 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * 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/>.
- */
-
-package com.nextcloud.talk.adapters.messages;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.TextView;
-import androidx.core.view.ViewCompat;
-import androidx.emoji.widget.EmojiTextView;
-
-import autodagger.AutoInjector;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.google.android.flexbox.FlexboxLayout;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.models.json.chat.ChatMessage;
-import com.nextcloud.talk.utils.DisplayUtils;
-import com.nextcloud.talk.utils.TextMatchers;
-import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.stfalcon.chatkit.messages.MessageHolders;
-
-import javax.inject.Inject;
-import java.util.HashMap;
-import java.util.Map;
-
-@AutoInjector(NextcloudTalkApplication.class)
-public class MagicOutcomingTextMessageViewHolder extends MessageHolders.OutcomingTextMessageViewHolder<ChatMessage> {
-    @BindView(R.id.messageText)
-    EmojiTextView messageText;
-
-    @BindView(R.id.messageTime)
-    TextView messageTimeView;
-
-    @Inject
-    UserUtils userUtils;
-
-    @Inject
-    Context context;
-
-    private View itemView;
-
-    public MagicOutcomingTextMessageViewHolder(View itemView) {
-        super(itemView);
-        ButterKnife.bind(this, itemView);
-        NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
-
-        this.itemView = itemView;
-    }
-
-    @Override
-    public void onBind(ChatMessage message) {
-        super.onBind(message);
-
-        HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
-
-        Spannable messageString = new SpannableString(message.getText());
-
-        itemView.setSelected(false);
-        messageTimeView.setTextColor(context.getResources().getColor(R.color.white60));
-
-        FlexboxLayout.LayoutParams layoutParams = (FlexboxLayout.LayoutParams) messageTimeView.getLayoutParams();
-        layoutParams.setWrapBefore(false);
-
-        float textSize = context.getResources().getDimension(R.dimen.chat_text_size);
-
-        if (messageParameters != null && messageParameters.size() > 0) {
-            for (String key : messageParameters.keySet()) {
-                Map<String, String> individualHashMap = message.getMessageParameters().get(key);
-                if (individualHashMap != null) {
-                    if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
-                        messageString =
-                                DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
-                                        messageString,
-                                        individualHashMap.get("id"),
-                                        individualHashMap.get("name"),
-                                        individualHashMap.get("type"),
-                                        userUtils.getUserById(message.getActiveUser().getUserId()),
-                                        R.xml.chip_others);
-                    } else if (individualHashMap.get("type").equals("file")) {
-                        itemView.setOnClickListener(v -> {
-                            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
-                            context.startActivity(browserIntent);
-                        });
-
-                    }
-                }
-            }
-
-        } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())) {
-            textSize = (float) (textSize * 2.5);
-            layoutParams.setWrapBefore(true);
-            messageTimeView.setTextColor(context.getResources().getColor(R.color.warm_grey_four));
-            itemView.setSelected(true);
-        }
-
-        Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
-        if (message.isGrouped) {
-            Drawable bubbleDrawable =
-                    DisplayUtils.getMessageSelector(resources.getColor(R.color.bg_message_list_outcoming_bubble),
-                    resources.getColor(R.color.transparent),
-                    resources.getColor(R.color.bg_message_list_outcoming_bubble), R.drawable.shape_grouped_outcoming_message);
-            ViewCompat.setBackground(bubble, bubbleDrawable);
-        } else {
-            Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.bg_message_list_outcoming_bubble),
-                    resources.getColor(R.color.transparent),
-                    resources.getColor(R.color.bg_message_list_outcoming_bubble), R.drawable.shape_outcoming_message);
-            ViewCompat.setBackground(bubble, bubbleDrawable);
-        }
-
-        messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-        messageTimeView.setLayoutParams(layoutParams);
-        messageText.setText(messageString);
-    }
-}

+ 182 - 0
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.kt

@@ -0,0 +1,182 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * 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/>.
+ */
+package com.nextcloud.talk.adapters.messages
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.text.Spannable
+import android.text.SpannableString
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.RelativeLayout
+import android.widget.TextView
+import androidx.core.view.ViewCompat
+import androidx.emoji.widget.EmojiTextView
+import autodagger.AutoInjector
+import butterknife.BindView
+import butterknife.ButterKnife
+import com.facebook.drawee.view.SimpleDraweeView
+import com.google.android.flexbox.FlexboxLayout
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
+import com.nextcloud.talk.models.json.chat.ChatMessage
+import com.nextcloud.talk.utils.DisplayUtils.getMessageSelector
+import com.nextcloud.talk.utils.DisplayUtils.searchAndReplaceWithMentionSpan
+import com.nextcloud.talk.utils.TextMatchers
+import com.stfalcon.chatkit.messages.MessageHolders.OutcomingTextMessageViewHolder
+import com.stfalcon.chatkit.utils.DateFormatter
+import java.util.*
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewHolder<ChatMessage>(itemView) {
+    @JvmField
+    @BindView(R.id.messageText)
+    var messageText: EmojiTextView? = null
+    @JvmField
+    @BindView(R.id.messageTime)
+    var messageTimeView: TextView? = null
+
+    @JvmField
+    @BindView(R.id.quotedChatMessageView)
+    var quotedChatMessageView: RelativeLayout? = null
+
+    @JvmField
+    @BindView(R.id.quotedUserAvatar)
+    var quotedUserAvatar: SimpleDraweeView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessageAuthor)
+    var quotedUserName: EmojiTextView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessageImage)
+    var quotedMessagePreview: SimpleDraweeView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessage)
+    var quotedMessage: EmojiTextView? = null
+
+    @JvmField
+    @BindView(R.id.quotedMessageTime)
+    var quotedMessageTime: TextView? = null
+
+    @JvmField
+    @BindView(R.id.quoteColoredView)
+    var quoteColoredView: View? = null
+
+    @JvmField
+    @Inject
+    var context: Context? = null
+
+    private val realView: View
+    override fun onBind(message: ChatMessage) {
+        super.onBind(message)
+        sharedApplication!!.componentApplication.inject(this)
+        val messageParameters: HashMap<String, HashMap<String, String>>? = message.messageParameters
+        var messageString: Spannable = SpannableString(message.text)
+        realView.isSelected = false
+        messageTimeView!!.setTextColor(context!!.resources.getColor(R.color.white60))
+        val layoutParams = messageTimeView!!.layoutParams as FlexboxLayout.LayoutParams
+        layoutParams.isWrapBefore = false
+        var textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
+        if (messageParameters != null && messageParameters.size > 0) {
+            for (key in messageParameters.keys) {
+                val individualHashMap: HashMap<String, String>? = message.messageParameters[key]
+                if (individualHashMap != null) {
+                    if (individualHashMap["type"] == "user" || (individualHashMap["type"]
+                                    == "guest") || individualHashMap["type"] == "call") {
+                        messageString = searchAndReplaceWithMentionSpan(messageText!!.context,
+                                messageString,
+                                individualHashMap["id"]!!,
+                                individualHashMap["name"]!!,
+                                individualHashMap["type"]!!,
+                                message.activeUser,
+                                R.xml.chip_others)
+                    } else if (individualHashMap["type"] == "file") {
+                        realView.setOnClickListener(View.OnClickListener { v: View? ->
+                            val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
+                            context!!.startActivity(browserIntent)
+                        })
+                    }
+                }
+            }
+        } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
+            textSize = (textSize * 2.5).toFloat()
+            layoutParams.isWrapBefore = true
+            messageTimeView!!.setTextColor(context!!.resources.getColor(R.color.warm_grey_four))
+            realView.isSelected = true
+        }
+        val resources = sharedApplication!!.resources
+        if (message.isGrouped) {
+            val bubbleDrawable = getMessageSelector(
+                    resources.getColor(R.color.bg_message_list_outcoming_bubble),
+                    resources.getColor(R.color.transparent),
+                    resources.getColor(R.color.bg_message_list_outcoming_bubble),
+                    R.drawable.shape_grouped_outcoming_message)
+            ViewCompat.setBackground(bubble, bubbleDrawable)
+        } else {
+            val bubbleDrawable = getMessageSelector(
+                    resources.getColor(R.color.bg_message_list_outcoming_bubble),
+                    resources.getColor(R.color.transparent),
+                    resources.getColor(R.color.bg_message_list_outcoming_bubble),
+                    R.drawable.shape_outcoming_message)
+            ViewCompat.setBackground(bubble, bubbleDrawable)
+        }
+        messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
+        messageTimeView!!.layoutParams = layoutParams
+        messageText!!.text = messageString
+
+        // parent message handling
+
+        message.parentMessage?.let { parentChatMessage ->
+            parentChatMessage.activeUser = message.activeUser
+            imageLoader.loadImage(quotedUserAvatar, parentChatMessage.user.avatar, null)
+            parentChatMessage.imageUrl?.let{
+                quotedMessagePreview?.visibility = View.VISIBLE
+                imageLoader.loadImage(quotedMessagePreview, it, null)
+            } ?: run {
+                quotedMessagePreview?.visibility = View.GONE
+            }
+            quotedUserName?.text = parentChatMessage.actorDisplayName
+                    ?: context!!.getText(R.string.nc_nick_guest)
+            quotedMessage?.text = parentChatMessage.text
+            quotedMessage?.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default))
+            quotedUserName?.setTextColor(context!!.resources.getColor(R.color.nc_grey))
+
+            quotedMessageTime?.text = DateFormatter.format(parentChatMessage.createdAt, DateFormatter.Template.TIME)
+            quotedMessageTime?.setTextColor(context!!.resources.getColor(R.color.white60))
+            quoteColoredView?.setBackgroundResource(R.color.white)
+
+            quotedChatMessageView?.visibility = View.VISIBLE
+        } ?: run {
+            quotedChatMessageView?.visibility = View.GONE
+        }
+
+    }
+
+    init {
+        ButterKnife.bind(this, itemView)
+        this.realView = itemView
+    }
+}

+ 8 - 8
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java

@@ -81,8 +81,8 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
     public void onBind(ChatMessage message) {
         super.onBind(message);
         if (userAvatar != null) {
-            if (message.isGrouped || message.isOneToOneConversation()) {
-                if (message.isOneToOneConversation()) {
+            if (message.isGrouped || message.isOneToOneConversation) {
+                if (message.isOneToOneConversation) {
                     userAvatar.setVisibility(View.GONE);
                 } else {
                     userAvatar.setVisibility(View.INVISIBLE);
@@ -90,7 +90,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
             } else {
                 userAvatar.setVisibility(View.VISIBLE);
 
-                if ("bots".equals(message.getActorType()) && "changelog".equals(message.getActorId())) {
+                if ("bots".equals(message.actorType) && "changelog".equals(message.actorId)) {
                     Drawable[] layers = new Drawable[2];
                     layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
                     layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
@@ -108,13 +108,13 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
             if (message.getSelectedIndividualHashMap().containsKey("mimetype")) {
                 image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(message.getSelectedIndividualHashMap().get("mimetype"))));
             } else {
-                fetchFileInformation("/" + message.getSelectedIndividualHashMap().get("path"), message.getActiveUser());
+                fetchFileInformation("/" + message.getSelectedIndividualHashMap().get("path"), message.activeUser);
             }
 
             image.setOnClickListener(v -> {
 
                 String accountString =
-                        message.getActiveUser().getUsername() + "@" + message.getActiveUser().getBaseUrl().replace("https://", "").replace("http://", "");
+                        message.activeUser.getUsername() + "@" + message.activeUser.getBaseUrl().replace("https://", "").replace("http://", "");
 
                 if (AccountUtils.INSTANCE.canWeOpenFilesApp(context, accountString)) {
                     Intent filesAppIntent = new Intent(Intent.ACTION_VIEW, null);
@@ -167,10 +167,10 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
                     @Override
                     public void onSuccess(ReadFilesystemOperation readFilesystemOperation) {
                         DavResponse davResponse = readFilesystemOperation.readRemotePath();
-                        if (davResponse.getData() != null) {
-                            List<BrowserFile> browserFileList = (List<BrowserFile>) davResponse.getData();
+                        if (davResponse.data != null) {
+                            List<BrowserFile> browserFileList = (List<BrowserFile>) davResponse.data;
                             if (!browserFileList.isEmpty()) {
-                                new Handler(context.getMainLooper()).post(() -> image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(browserFileList.get(0).getMimeType()))));
+                                new Handler(context.getMainLooper()).post(() -> image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(browserFileList.get(0).mimeType))));
                             }
                         }
                     }

+ 3 - 3
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicSystemMessageViewHolder.java

@@ -72,9 +72,9 @@ public class MagicSystemMessageViewHolder extends MessageHolders.IncomingTextMes
 
         Spannable messageString = new SpannableString(message.getText());
 
-        if (message.getMessageParameters() != null && message.getMessageParameters().size() > 0) {
-            for (String key : message.getMessageParameters().keySet()) {
-                Map<String, String> individualHashMap = message.getMessageParameters().get(key);
+        if (message.messageParameters != null && message.messageParameters.size() > 0) {
+            for (String key : message.messageParameters.keySet()) {
+                Map<String, String> individualHashMap = message.messageParameters.get(key);
                 if (individualHashMap != null && (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call"))) {
                     messageString = DisplayUtils.searchAndColor(messageString, "@" + individualHashMap.get("name"), mentionColor);
                 }

+ 2 - 2
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/DavResponse.java

@@ -25,6 +25,6 @@ import lombok.Data;
 
 @Data
 public class DavResponse {
-    Response response;
-    Object data;
+    public Response response;
+    public Object data;
 }

+ 2 - 2
app/src/main/java/com/nextcloud/talk/models/SignatureVerification.java

@@ -28,6 +28,6 @@ import org.parceler.Parcel;
 @Data
 @Parcel
 public class SignatureVerification {
-    boolean signatureValid;
-    UserEntity userEntity;
+    public boolean signatureValid;
+    public UserEntity userEntity;
 }

+ 9 - 3
app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java

@@ -52,9 +52,6 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
     public Map<String, String> selectedIndividualHashMap;
     @JsonIgnore
     public boolean isLinkPreviewAllowed;
-    List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE,
-            MessageType.SYSTEM_MESSAGE, MessageType.SINGLE_LINK_VIDEO_MESSAGE,
-            MessageType.SINGLE_LINK_AUDIO_MESSAGE, MessageType.SINGLE_LINK_MESSAGE);
     @JsonField(name = "id")
     public int jsonMessageId;
     @JsonField(name = "token")
@@ -76,6 +73,15 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
     public HashMap<String, HashMap<String, String>> messageParameters;
     @JsonField(name = "systemMessage", typeConverter = EnumSystemMessageTypeConverter.class)
     public SystemMessageType systemMessageType;
+    @JsonField(name = "isReplyable")
+    public boolean replyable;
+    @JsonField(name = "parent")
+    public ChatMessage parentMessage;
+
+    @JsonIgnore
+    List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE,
+            MessageType.SYSTEM_MESSAGE, MessageType.SINGLE_LINK_VIDEO_MESSAGE,
+            MessageType.SINGLE_LINK_AUDIO_MESSAGE, MessageType.SINGLE_LINK_MESSAGE);
 
     private boolean hasFileAttachment() {
         if (messageParameters != null && messageParameters.size() > 0) {

+ 37 - 51
app/src/main/res/layout/item_custom_incoming_preview_message.xml

@@ -20,72 +20,58 @@
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_marginStart="16dp"
     android:layout_marginTop="2dp"
     android:layout_marginEnd="16dp"
     android:layout_marginBottom="2dp">
 
-    <RelativeLayout
+    <com.google.android.flexbox.FlexboxLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_toEndOf="@id/messageUserAvatar">
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp"
+        android:orientation="vertical"
+        android:layout_alignParentStart="true"
+        app:alignContent="stretch"
+        app:alignItems="stretch"
+        app:flexWrap="wrap"
+        app:justifyContent="flex_end">
 
         <com.facebook.drawee.view.SimpleDraweeView
             android:id="@id/image"
-            android:layout_width="@dimen/minimum_file_preview_size"
-            android:layout_height="@dimen/minimum_file_preview_size"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:adjustViewBounds="true"
-            app:actualImageScaleType="fitCenter" />
+            android:scaleType="fitCenter"
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true"
+            app:layout_alignSelf="flex_start"
+            tools:src="@tools:sample/backgrounds/scenic"/>
 
-        <com.google.android.flexbox.FlexboxLayout
+        <androidx.emoji.widget.EmojiTextView
+            android:id="@id/messageText"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_below="@id/image"
-            android:layout_alignStart="@+id/image"
-            android:layout_alignEnd="@id/image"
-            android:layout_marginTop="8dp"
-            android:layout_marginBottom="8dp"
-            android:orientation="vertical"
-            app:alignContent="stretch"
-            app:alignItems="stretch"
-            app:flexWrap="wrap"
-            app:justifyContent="flex_end">
-
-            <androidx.emoji.widget.EmojiTextView
-                android:id="@id/messageText"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:autoLink="none"
-                android:textColor="@color/warm_grey_four"
-                android:textColorLink="@color/warm_grey_four"
-                android:textIsSelectable="true"
-                android:textSize="12sp"
-                app:layout_alignSelf="flex_start"
-                app:layout_flexGrow="1"
-                app:layout_wrapBefore="true" />
-
-            <TextView
-                android:id="@id/messageTime"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentEnd="true"
-                android:layout_marginStart="8dp"
-                android:textColor="@color/warm_grey_four"
-                app:layout_alignSelf="center" />
+            android:autoLink="none"
+            android:textColor="@color/warm_grey_four"
+            android:textColorLink="@color/warm_grey_four"
+            android:textIsSelectable="true"
+            android:textSize="12sp"
+            app:layout_alignSelf="flex_start"
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true" />
 
-        </com.google.android.flexbox.FlexboxLayout>
-
-    </RelativeLayout>
-
-    <com.facebook.drawee.view.SimpleDraweeView
-        android:id="@id/messageUserAvatar"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginEnd="8dp"
-        app:roundAsCircle="true" />
+        <TextView
+            android:id="@id/messageTime"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_marginStart="8dp"
+            android:textColor="@color/warm_grey_four"
+            app:layout_alignSelf="center" />
+    </com.google.android.flexbox.FlexboxLayout>
 
 </RelativeLayout>

+ 2 - 0
app/src/main/res/layout/item_custom_incoming_text_message.xml

@@ -47,6 +47,8 @@
         app:flexWrap="wrap"
         app:justifyContent="flex_end">
 
+        <include layout="@layout/item_message_quote" android:visibility="gone"/>
+
         <androidx.emoji.widget.EmojiTextView
             android:id="@+id/messageAuthor"
             android:layout_width="match_parent"

+ 16 - 12
app/src/main/res/layout/item_custom_outcoming_preview_message.xml

@@ -20,35 +20,38 @@
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_marginStart="16dp"
     android:layout_marginTop="2dp"
     android:layout_marginEnd="16dp"
     android:layout_marginBottom="2dp">
 
-    <com.facebook.drawee.view.SimpleDraweeView
-        android:id="@id/image"
-        android:layout_width="@dimen/minimum_file_preview_size"
-        android:layout_height="@dimen/minimum_file_preview_size"
-        android:layout_alignParentEnd="true"
-        android:adjustViewBounds="true"
-        app:actualImageScaleType="fitCenter" />
-
     <com.google.android.flexbox.FlexboxLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_below="@id/image"
-        android:layout_alignStart="@+id/image"
-        android:layout_alignEnd="@id/image"
         android:layout_marginTop="8dp"
         android:layout_marginBottom="8dp"
         android:orientation="vertical"
+        android:layout_alignParentEnd="true"
         app:alignContent="stretch"
         app:alignItems="stretch"
         app:flexWrap="wrap"
         app:justifyContent="flex_end">
 
+        <com.facebook.drawee.view.SimpleDraweeView
+            android:id="@id/image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:adjustViewBounds="true"
+            android:scaleType="fitCenter"
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true"
+            app:layout_alignSelf="flex_start"
+            app:actualImageScaleType="fitCenter"
+            tools:src="@tools:sample/backgrounds/scenic"/>
+
         <androidx.emoji.widget.EmojiTextView
             android:id="@id/messageText"
             android:layout_width="wrap_content"
@@ -67,6 +70,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_alignParentEnd="true"
+            android:layout_marginStart="8dp"
             android:textColor="@color/warm_grey_four"
             app:layout_alignSelf="center" />
     </com.google.android.flexbox.FlexboxLayout>

+ 2 - 0
app/src/main/res/layout/item_custom_outcoming_text_message.xml

@@ -38,6 +38,8 @@
         app:flexWrap="wrap"
         app:justifyContent="flex_end">
 
+        <include layout="@layout/item_message_quote" android:visibility="gone"/>
+
         <androidx.emoji.widget.EmojiTextView
             android:id="@id/messageText"
             android:layout_width="wrap_content"

+ 90 - 0
app/src/main/res/layout/item_message_quote.xml

@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/quotedChatMessageView"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <View
+        android:id="@+id/quoteColoredView"
+        android:layout_width="2dp"
+        android:layout_height="match_parent"
+        android:layout_alignBottom="@id/flexboxQuoted"
+        android:layout_alignParentStart="true"
+        android:layout_marginEnd="4dp"
+        android:background="@color/colorPrimary"></View>
+
+    <com.facebook.drawee.view.SimpleDraweeView
+        android:id="@+id/quotedUserAvatar"
+        android:layout_width="8dp"
+        android:layout_height="8dp"
+        android:scaleType="centerInside"
+        android:adjustViewBounds="true"
+        app:roundAsCircle="true"
+        android:layout_alignParentTop="true"
+        android:layout_toEndOf="@id/quoteColoredView"
+        android:layout_marginEnd="4dp"
+        tools:src="@tools:sample/avatars[0]" />
+
+    <androidx.emoji.widget.EmojiTextView
+        android:id="@+id/quotedMessageAuthor"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@id/quotedUserAvatar"
+        android:layout_toEndOf="@id/quotedUserAvatar"
+        android:ellipsize="end"
+        android:layout_marginEnd="8dp"
+        android:textSize="12sp"
+        tools:text="Mario" />
+
+    <com.google.android.flexbox.FlexboxLayout
+        android:id="@+id/flexboxQuoted"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/quotedUserAvatar"
+        android:layout_alignStart="@id/quotedUserAvatar"
+        android:layout_marginTop="4dp"
+        android:orientation="vertical"
+        app:alignContent="stretch"
+        app:alignItems="stretch"
+        app:flexWrap="wrap"
+        app:justifyContent="flex_end">
+
+        <com.facebook.drawee.view.SimpleDraweeView
+            android:id="@+id/quotedMessageImage"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:adjustViewBounds="true"
+            android:scaleType="centerInside"
+            app:layout_alignSelf="flex_start"
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true"
+            tools:src="@tools:sample/backgrounds/scenic" />
+
+        <androidx.emoji.widget.EmojiTextView
+            android:id="@+id/quotedMessage"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="14sp"
+            android:layout_below="@id/quotedMessageImage"
+            android:layout_alignStart="@id/quotedUserAvatar"
+            android:lineSpacingMultiplier="1.2"
+            app:layout_alignSelf="flex_start"
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true"
+            tools:text="Hello, this is me!" />
+
+        <TextView
+            android:id="@+id/quotedMessageTime"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:textSize="12sp"
+            app:layout_alignSelf="center"
+            tools:text="16:08" />
+        />
+
+    </com.google.android.flexbox.FlexboxLayout>
+
+</RelativeLayout>

+ 1 - 1
app/src/main/res/layout/rv_item_browser_file.xml

@@ -19,9 +19,9 @@
   -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="@dimen/rv_item_view_height"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_margin="@dimen/double_margin_between_elements"
     android:background="@color/bg_default">
 

+ 24 - 0
app/src/main/res/values/ints.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ 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/>.
+  -->
+
+<resources>
+    <integer name="password_strike">320</integer>
+</resources>