瀏覽代碼

Merge pull request #1334 from nextcloud/bugfix/1135/use-the-contacts-photo-and-name

Show "contact-name" and "contact-photo" when applicable
Marcel Hibbe 4 年之前
父節點
當前提交
9f29d8c6ca

+ 34 - 1
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java

@@ -23,6 +23,7 @@ package com.nextcloud.talk.adapters.messages;
 import android.view.View;
 import android.widget.ProgressBar;
 
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.databinding.ItemCustomIncomingPreviewMessageBinding;
 
 import androidx.emoji.widget.EmojiTextView;
@@ -35,11 +36,43 @@ public class IncomingPreviewMessageViewHolder extends MagicPreviewMessageViewHol
         binding = ItemCustomIncomingPreviewMessageBinding.bind(itemView);
     }
 
-    public EmojiTextView getMessageText()  {
+    @Override
+    public EmojiTextView getMessageText() {
         return binding.messageText;
     }
 
+    @Override
     public ProgressBar getProgressBar() {
         return binding.progressBar;
     }
+
+    @Override
+    public SimpleDraweeView getImage() {
+        return binding.image;
+    }
+
+    @Override
+    public View getPreviewContainer() {
+        return binding.previewContainer;
+    }
+
+    @Override
+    public View getPreviewContactContainer() {
+        return binding.contactContainer;
+    }
+
+    @Override
+    public SimpleDraweeView getPreviewContactPhoto() {
+        return binding.contactPhoto;
+    }
+
+    @Override
+    public EmojiTextView getPreviewContactName() {
+        return binding.contactName;
+    }
+
+    @Override
+    public ProgressBar getPreviewContactProgressBar() {
+        return binding.contactProgressBar;
+    }
 }

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

@@ -33,12 +33,14 @@ import android.graphics.drawable.LayerDrawable;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Handler;
+import android.util.Base64;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.PopupMenu;
 import android.widget.ProgressBar;
 
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.activities.FullScreenImageActivity;
@@ -58,7 +60,9 @@ import com.nextcloud.talk.utils.DrawableUtils;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.stfalcon.chatkit.messages.MessageHolders;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -86,6 +90,14 @@ import static com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback.REPLYABLE_
 public abstract class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageMessageViewHolder<ChatMessage> {
 
     private static final String TAG = "PreviewMsgViewHolder";
+    public static final String KEY_CONTACT_NAME = "contact-name";
+    public static final String KEY_CONTACT_PHOTO = "contact-photo";
+    public static final String KEY_MIMETYPE = "mimetype";
+    public static final String KEY_ID = "id";
+    public static final String KEY_PATH = "path";
+    public static final String ACTOR_TYPE_BOTS = "bots";
+    public static final String ACTOR_ID_CHANGELOG = "changelog";
+    public static final String KEY_NAME = "name";
 
     @Inject
     Context context;
@@ -93,6 +105,10 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
     @Inject
     OkHttpClient okHttpClient;
 
+    ProgressBar progressBar;
+
+    View clickView;
+
     public MagicPreviewMessageViewHolder(View itemView) {
         super(itemView);
         NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
@@ -112,34 +128,62 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
             } else {
                 userAvatar.setVisibility(View.VISIBLE);
 
-                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);
-                    LayerDrawable layerDrawable = new LayerDrawable(layers);
+                if (ACTOR_TYPE_BOTS.equals(message.actorType) && ACTOR_ID_CHANGELOG.equals(message.actorId)) {
+                    if (context != null) {
+                        Drawable[] layers = new Drawable[2];
+                        layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background);
+                        layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground);
+                        LayerDrawable layerDrawable = new LayerDrawable(layers);
 
-                    userAvatar.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
+                        userAvatar.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
+                    }
                 }
             }
         }
 
+        progressBar = getProgressBar();
+        image = getImage();
+        clickView = getImage();
+        getMessageText().setVisibility(View.VISIBLE);
+
         if (message.getMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) {
-            String fileName = message.getSelectedIndividualHashMap().get("name");
+
+            String fileName = message.getSelectedIndividualHashMap().get(KEY_NAME);
             getMessageText().setText(fileName);
-            if (message.getSelectedIndividualHashMap().containsKey("mimetype")) {
-                String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
+            if (message.getSelectedIndividualHashMap().containsKey(KEY_CONTACT_NAME)) {
+                getPreviewContainer().setVisibility(View.GONE);
+                getPreviewContactName().setText(message.getSelectedIndividualHashMap().get(KEY_CONTACT_NAME));
+                progressBar = getPreviewContactProgressBar();
+                getMessageText().setVisibility(View.INVISIBLE);
+                clickView = getPreviewContactContainer();
+            } else {
+                getPreviewContainer().setVisibility(View.VISIBLE);
+                getPreviewContactContainer().setVisibility(View.GONE);
+            }
+
+            if (message.getSelectedIndividualHashMap().containsKey(KEY_CONTACT_PHOTO)) {
+                image = getPreviewContactPhoto();
+                Drawable drawable = getDrawableFromContactDetails(
+                        context,
+                        message.getSelectedIndividualHashMap().get(KEY_CONTACT_PHOTO));
+                image.getHierarchy().setPlaceholderImage(drawable);
+            } else if (message.getSelectedIndividualHashMap().containsKey(KEY_MIMETYPE)) {
+                String mimetype = message.getSelectedIndividualHashMap().get(KEY_MIMETYPE);
                 int drawableResourceId = DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(mimetype);
                 Drawable drawable = ContextCompat.getDrawable(context, drawableResourceId);
                 image.getHierarchy().setPlaceholderImage(drawable);
             } else {
-                fetchFileInformation("/" + message.getSelectedIndividualHashMap().get("path"), message.activeUser);
+                fetchFileInformation("/" + message.getSelectedIndividualHashMap().get(KEY_PATH), message.activeUser);
             }
 
             String accountString =
-                    message.activeUser.getUsername() + "@" + message.activeUser.getBaseUrl().replace("https://", "").replace("http://", "");
+                    message.activeUser.getUsername() + "@" +
+                            message.activeUser.getBaseUrl()
+                                    .replace("https://", "")
+                                    .replace("http://", "");
 
-            image.setOnClickListener(v -> {
-                String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
+            clickView.setOnClickListener(v -> {
+                String mimetype = message.getSelectedIndividualHashMap().get(KEY_MIMETYPE);
                 if (isSupportedForInternalViewer(mimetype) || canBeHandledByExternalApp(mimetype, fileName)) {
                     openOrDownloadFile(message);
                 } else {
@@ -147,25 +191,27 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
                 }
             });
 
-            image.setOnLongClickListener(l -> {
+            clickView.setOnLongClickListener(l -> {
                 onMessageViewLongClick(message, accountString);
                 return true;
             });
 
             // check if download worker is already running
-            String fileId = message.getSelectedIndividualHashMap().get("id");
+            String fileId = message.getSelectedIndividualHashMap().get(KEY_ID);
             ListenableFuture<List<WorkInfo>> workers = WorkManager.getInstance(context).getWorkInfosByTag(fileId);
 
             try {
                 for (WorkInfo workInfo : workers.get()) {
-                    if (workInfo.getState() == WorkInfo.State.RUNNING || workInfo.getState() == WorkInfo.State.ENQUEUED) {
-                        getProgressBar().setVisibility(View.VISIBLE);
+                    if (workInfo.getState() == WorkInfo.State.RUNNING ||
+                            workInfo.getState() == WorkInfo.State.ENQUEUED) {
+                        progressBar.setVisibility(View.VISIBLE);
 
-                        String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
+                        String mimetype = message.getSelectedIndividualHashMap().get(KEY_MIMETYPE);
 
-                        WorkManager.getInstance(context).getWorkInfoByIdLiveData(workInfo.getId()).observeForever(info -> {
-                            updateViewsByProgress(fileName, mimetype, info);
-                        });
+                        WorkManager
+                                .getInstance(context)
+                                .getWorkInfoByIdLiveData(workInfo.getId())
+                                .observeForever(info -> updateViewsByProgress(fileName, mimetype, info));
                     }
                 }
             } catch (ExecutionException | InterruptedException e) {
@@ -179,13 +225,13 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
             DisplayUtils.setClickableString("Tenor", "https://tenor.com", getMessageText());
         } else {
             if (message.getMessageType().equals(ChatMessage.MessageType.SINGLE_LINK_IMAGE_MESSAGE)) {
-                image.setOnClickListener(v -> {
+                clickView.setOnClickListener(v -> {
                     Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getImageUrl()));
                     browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     context.startActivity(browserIntent);
                 });
             } else {
-                image.setOnClickListener(null);
+                clickView.setOnClickListener(null);
             }
             getMessageText().setText("");
         }
@@ -193,13 +239,44 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
         itemView.setTag(REPLYABLE_VIEW_TAG, message.isReplyable());
     }
 
+
+    private Drawable getDrawableFromContactDetails(Context context, String base64) {
+        Drawable drawable = null;
+        if (!base64.equals("")) {
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(
+                    Base64.decode(base64.getBytes(), Base64.DEFAULT));
+            drawable = Drawable.createFromResourceStream(context.getResources(),
+                                                    null, inputStream, null, null);
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+                int drawableResourceId = DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType("text/vcard");
+                drawable = ContextCompat.getDrawable(context, drawableResourceId);
+            }
+        }
+
+        return drawable;
+    }
+
     public abstract EmojiTextView getMessageText();
 
     public abstract ProgressBar getProgressBar();
 
+    public abstract SimpleDraweeView getImage();
+
+    public abstract View getPreviewContainer();
+
+    public abstract View getPreviewContactContainer();
+
+    public abstract SimpleDraweeView getPreviewContactPhoto();
+
+    public abstract EmojiTextView getPreviewContactName();
+
+    public abstract ProgressBar getPreviewContactProgressBar();
+
     private void openOrDownloadFile(ChatMessage message) {
-        String filename = message.getSelectedIndividualHashMap().get("name");
-        String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
+        String filename = message.getSelectedIndividualHashMap().get(KEY_NAME);
+        String mimetype = message.getSelectedIndividualHashMap().get(KEY_MIMETYPE);
         File file = new File(context.getCacheDir(), filename);
         if (file.exists()) {
             openFile(filename, mimetype);
@@ -302,22 +379,31 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
     private void openFileInFilesApp(ChatMessage message, String accountString) {
         if (AccountUtils.INSTANCE.canWeOpenFilesApp(context, accountString)) {
             Intent filesAppIntent = new Intent(Intent.ACTION_VIEW, null);
-            final ComponentName componentName = new ComponentName(context.getString(R.string.nc_import_accounts_from), "com.owncloud.android.ui.activity.FileDisplayActivity");
+            final ComponentName componentName = new ComponentName(
+                    context.getString(R.string.nc_import_accounts_from),
+                    "com.owncloud.android.ui.activity.FileDisplayActivity"
+            );
             filesAppIntent.setComponent(componentName);
             filesAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             filesAppIntent.setPackage(context.getString(R.string.nc_import_accounts_from));
             filesAppIntent.putExtra(BundleKeys.INSTANCE.getKEY_ACCOUNT(), accountString);
-            filesAppIntent.putExtra(BundleKeys.INSTANCE.getKEY_FILE_ID(), message.getSelectedIndividualHashMap().get("id"));
+            filesAppIntent.putExtra(
+                    BundleKeys.INSTANCE.getKEY_FILE_ID(),
+                    message.getSelectedIndividualHashMap().get(KEY_ID)
+                                   );
             context.startActivity(filesAppIntent);
         } else {
-            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getSelectedIndividualHashMap().get("link")));
+            Intent browserIntent = new Intent(
+                    Intent.ACTION_VIEW,
+                    Uri.parse(message.getSelectedIndividualHashMap().get("link"))
+            );
             browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             context.startActivity(browserIntent);
         }
     }
 
     private void onMessageViewLongClick(ChatMessage message, String accountString) {
-        if (isSupportedForInternalViewer(message.getSelectedIndividualHashMap().get("mimetype"))) {
+        if (isSupportedForInternalViewer(message.getSelectedIndividualHashMap().get(KEY_MIMETYPE))) {
             return;
         }
 
@@ -339,8 +425,8 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
         String userId = message.activeUser.getUserId();
         String attachmentFolder = CapabilitiesUtil.getAttachmentFolder(message.activeUser);
 
-        String fileName = message.getSelectedIndividualHashMap().get("name");
-        String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
+        String fileName = message.getSelectedIndividualHashMap().get(KEY_NAME);
+        String mimetype = message.getSelectedIndividualHashMap().get(KEY_MIMETYPE);
 
         String size = message.getSelectedIndividualHashMap().get("size");
 
@@ -349,8 +435,8 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
         }
         Integer fileSize = Integer.valueOf(size);
 
-        String fileId = message.getSelectedIndividualHashMap().get("id");
-        String path = message.getSelectedIndividualHashMap().get("path");
+        String fileId = message.getSelectedIndividualHashMap().get(KEY_ID);
+        String path = message.getSelectedIndividualHashMap().get(KEY_PATH);
 
         // check if download worker is already running
         ListenableFuture<List<WorkInfo>> workers = WorkManager.getInstance(context).getWorkInfosByTag(fileId);
@@ -386,7 +472,7 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
 
         WorkManager.getInstance().enqueue(downloadWorker);
 
-        getProgressBar().setVisibility(View.VISIBLE);
+        progressBar.setVisibility(View.VISIBLE);
 
         WorkManager.getInstance(context).getWorkInfoByIdLiveData(downloadWorker.getId()).observeForever(workInfo -> {
             updateViewsByProgress(fileName, mimetype, workInfo);
@@ -406,16 +492,16 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
                 if (image.isShown()) {
                     openFile(fileName, mimetype);
                 } else {
-                    Log.d(TAG, "file " + fileName + " was downloaded but it's not opened because view is not shown on" +
-                            " screen");
+                    Log.d(TAG, "file " + fileName +
+                            " was downloaded but it's not opened because view is not shown on screen");
                 }
                 getMessageText().setText(fileName);
-                getProgressBar().setVisibility(View.GONE);
+                progressBar.setVisibility(View.GONE);
                 break;
 
             case FAILED:
                 getMessageText().setText(fileName);
-                getProgressBar().setVisibility(View.GONE);
+                progressBar.setVisibility(View.GONE);
                 break;
             default:
                 // do nothing
@@ -471,7 +557,9 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
                             List<BrowserFile> browserFileList = (List<BrowserFile>) davResponse.data;
                             if (!browserFileList.isEmpty()) {
                                 new Handler(context.getMainLooper()).post(() -> {
-                                    int resourceId = DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(browserFileList.get(0).mimeType);
+                                    int resourceId = DrawableUtils
+                                            .INSTANCE
+                                            .getDrawableResourceIdForMimeType(browserFileList.get(0).mimeType);
                                     Drawable drawable = ContextCompat.getDrawable(context, resourceId);
                                     image.getHierarchy().setPlaceholderImage(drawable);
                                 });

+ 34 - 1
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java

@@ -23,6 +23,7 @@ package com.nextcloud.talk.adapters.messages;
 import android.view.View;
 import android.widget.ProgressBar;
 
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.databinding.ItemCustomOutcomingPreviewMessageBinding;
 
 import androidx.emoji.widget.EmojiTextView;
@@ -35,11 +36,43 @@ public class OutcomingPreviewMessageViewHolder extends MagicPreviewMessageViewHo
         binding = ItemCustomOutcomingPreviewMessageBinding.bind(itemView);
     }
 
-    public EmojiTextView getMessageText()  {
+    @Override
+    public EmojiTextView getMessageText() {
         return binding.messageText;
     }
 
+    @Override
     public ProgressBar getProgressBar() {
         return binding.progressBar;
     }
+
+    @Override
+    public SimpleDraweeView getImage() {
+        return binding.image;
+    }
+
+    @Override
+    public View getPreviewContainer() {
+        return binding.previewContainer;
+    }
+
+    @Override
+    public View getPreviewContactContainer() {
+        return binding.contactContainer;
+    }
+
+    @Override
+    public SimpleDraweeView getPreviewContactPhoto() {
+        return binding.contactPhoto;
+    }
+
+    @Override
+    public EmojiTextView getPreviewContactName() {
+        return binding.contactName;
+    }
+
+    @Override
+    public ProgressBar getPreviewContactProgressBar() {
+        return binding.contactProgressBar;
+    }
 }

+ 82 - 7
app/src/main/res/layout/item_custom_incoming_preview_message.xml

@@ -3,6 +3,8 @@
   ~
   ~ @author Mario Danic
   ~ @author Marcel Hibbe
+  ~ @author Andy Scherzinger
+  ~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
   ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
   ~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
   ~
@@ -22,12 +24,12 @@
 
 <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: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_marginEnd="14dp"
     android:layout_marginBottom="2dp">
 
     <com.facebook.drawee.view.SimpleDraweeView
@@ -35,7 +37,7 @@
         android:layout_width="24dp"
         android:layout_height="24dp"
         android:layout_alignParentTop="true"
-        android:layout_marginEnd="8dp"
+        android:layout_marginEnd="6dp"
         app:roundAsCircle="true" />
 
     <com.google.android.flexbox.FlexboxLayout
@@ -51,12 +53,16 @@
         app:justifyContent="flex_end">
 
         <FrameLayout
+            android:id="@+id/preview_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="2dp"
+            android:layout_marginEnd="2dp"
+            android:adjustViewBounds="true"
+            app:layout_alignSelf="flex_start"
             app:layout_flexGrow="1"
             app:layout_wrapBefore="true"
-            app:layout_alignSelf="flex_start"
-            android:adjustViewBounds="true">
+            tools:visibility="gone">
 
             <!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
             <com.facebook.drawee.view.SimpleDraweeView
@@ -75,10 +81,76 @@
                 android:visibility="gone" />
         </FrameLayout>
 
+        <com.google.android.material.card.MaterialCardView
+            android:id="@+id/contact_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="2dp"
+            android:layout_marginBottom="1dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="2dp"
+            app:layout_alignSelf="flex_start"
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true"
+            app:strokeWidth="0dp">
+
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:padding="@dimen/standard_padding">
+
+                <FrameLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:adjustViewBounds="true">
+
+                    <!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
+                    <com.facebook.drawee.view.SimpleDraweeView
+                        android:id="@+id/contact_photo"
+                        android:layout_width="@dimen/small_item_height"
+                        android:layout_height="@dimen/small_item_height"
+                        android:scaleType="fitStart"
+                        app:roundAsCircle="true"
+                        tools:src="@drawable/ic_call_black_24dp" />
+
+                    <ProgressBar
+                        android:id="@+id/contact_progress_bar"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:layout_gravity="center"
+                        android:visibility="gone"
+                        tools:visibility="visible" />
+                </FrameLayout>
+
+                <androidx.emoji.widget.EmojiTextView
+                    android:id="@+id/contact_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:autoLink="none"
+                    android:ellipsize="middle"
+                    android:gravity="center_vertical"
+                    android:maxLines="3"
+                    android:paddingStart="@dimen/standard_padding"
+                    android:paddingEnd="0dp"
+                    android:textColor="@color/high_emphasis_text"
+                    android:textColorLink="@color/high_emphasis_text"
+                    android:textIsSelectable="false"
+                    android:textSize="16sp"
+                    app:layout_alignSelf="flex_start"
+                    app:layout_flexGrow="1"
+                    app:layout_wrapBefore="true"
+                    tools:text="Charlotte D. Meyerheimers" />
+
+            </LinearLayout>
+
+        </com.google.android.material.card.MaterialCardView>
+
         <androidx.emoji.widget.EmojiTextView
             android:id="@id/messageText"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="2dp"
             android:autoLink="none"
             android:textColor="@color/warm_grey_four"
             android:textColorLink="@color/warm_grey_four"
@@ -86,7 +158,8 @@
             android:textSize="12sp"
             app:layout_alignSelf="flex_start"
             app:layout_flexGrow="1"
-            app:layout_wrapBefore="true" />
+            app:layout_wrapBefore="true"
+            tools:text="A simple message" />
 
         <TextView
             android:id="@id/messageTime"
@@ -94,8 +167,10 @@
             android:layout_height="wrap_content"
             android:layout_alignParentEnd="true"
             android:layout_marginStart="8dp"
+            android:layout_marginEnd="2dp"
             android:textColor="@color/warm_grey_four"
-            app:layout_alignSelf="center" />
+            app:layout_alignSelf="center"
+            tools:text="12:38" />
     </com.google.android.flexbox.FlexboxLayout>
 
 </RelativeLayout>

+ 79 - 7
app/src/main/res/layout/item_custom_outcoming_preview_message.xml

@@ -3,6 +3,8 @@
   ~
   ~ @author Mario Danic
   ~ @author Marcel Hibbe
+  ~ @author Andy Scherzinger
+  ~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
   ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
   ~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
   ~
@@ -22,33 +24,36 @@
 
 <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: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_marginEnd="14dp"
     android:layout_marginBottom="2dp">
 
     <com.google.android.flexbox.FlexboxLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
         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">
 
         <FrameLayout
+            android:id="@+id/preview_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            app:layout_flexGrow="1"
-            app:layout_wrapBefore="true"
+            android:layout_marginStart="2dp"
+            android:layout_marginEnd="2dp"
+            android:adjustViewBounds="true"
             app:layout_alignSelf="flex_start"
-            android:adjustViewBounds="true">
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true">
 
             <!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
             <com.facebook.drawee.view.SimpleDraweeView
@@ -67,15 +72,81 @@
                 android:visibility="gone" />
         </FrameLayout>
 
+        <com.google.android.material.card.MaterialCardView
+            android:id="@+id/contact_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="2dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="2dp"
+            app:layout_alignSelf="flex_start"
+            app:layout_flexGrow="1"
+            app:layout_wrapBefore="true"
+            app:strokeWidth="0dp">
+
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:padding="@dimen/standard_padding">
+
+                <FrameLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:adjustViewBounds="true">
+
+                    <!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
+                    <com.facebook.drawee.view.SimpleDraweeView
+                        android:id="@+id/contact_photo"
+                        android:layout_width="@dimen/small_item_height"
+                        android:layout_height="@dimen/small_item_height"
+                        android:scaleType="fitStart"
+                        app:roundAsCircle="true"
+                        tools:src="@drawable/ic_call_black_24dp" />
+
+                    <ProgressBar
+                        android:id="@+id/contact_progress_bar"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:layout_gravity="center"
+                        android:visibility="gone"
+                        tools:visibility="visible" />
+                </FrameLayout>
+
+                <androidx.emoji.widget.EmojiTextView
+                    android:id="@+id/contact_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:autoLink="none"
+                    android:ellipsize="middle"
+                    android:gravity="center_vertical"
+                    android:maxLines="3"
+                    android:paddingStart="@dimen/standard_padding"
+                    android:paddingEnd="0dp"
+                    android:textColor="@color/high_emphasis_text"
+                    android:textColorLink="@color/high_emphasis_text"
+                    android:textIsSelectable="false"
+                    android:textSize="16sp"
+                    app:layout_alignSelf="flex_start"
+                    app:layout_flexGrow="1"
+                    app:layout_wrapBefore="true"
+                    tools:text="Charlotte D. Meyerheimers" />
+
+            </LinearLayout>
+
+        </com.google.android.material.card.MaterialCardView>
+
         <androidx.emoji.widget.EmojiTextView
             android:id="@id/messageText"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="2dp"
             android:autoLink="none"
             android:textColor="@color/warm_grey_four"
             android:textColorLink="@color/warm_grey_four"
             android:textIsSelectable="true"
             android:textSize="12sp"
+            android:visibility="invisible"
             app:layout_alignSelf="flex_start"
             app:layout_flexGrow="1"
             app:layout_wrapBefore="true"
@@ -87,9 +158,10 @@
             android:layout_height="wrap_content"
             android:layout_alignParentEnd="true"
             android:layout_marginStart="8dp"
+            android:layout_marginEnd="2dp"
             android:textColor="@color/warm_grey_four"
             app:layout_alignSelf="center"
-            tools:text="12:34:56" />
+            tools:text="12:34" />
     </com.google.android.flexbox.FlexboxLayout>
 
 </RelativeLayout>

+ 1 - 1
scripts/analysis/lint-results.txt

@@ -1,2 +1,2 @@
 DO NOT TOUCH; GENERATED BY DRONE
-      <span class="mdl-layout-title">Lint Report: 3 errors and 275 warnings</span>
+      <span class="mdl-layout-title">Lint Report: 3 errors and 273 warnings</span>