Răsfoiți Sursa

Fix #253, Work on #268

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic 6 ani în urmă
părinte
comite
ef8a2b68fd
40 a modificat fișierele cu 693 adăugiri și 171 ștergeri
  1. 22 25
      app/src/main/java/com/nextcloud/talk/adapters/items/CallItem.java
  2. 292 0
      app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java
  3. 4 4
      app/src/main/java/com/nextcloud/talk/controllers/CallController.java
  4. 12 12
      app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java
  5. 46 22
      app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java
  6. 5 5
      app/src/main/java/com/nextcloud/talk/controllers/ChatController.java
  7. 4 4
      app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java
  8. 18 18
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java
  9. 12 12
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java
  10. 27 27
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java
  11. 4 4
      app/src/main/java/com/nextcloud/talk/events/MoreMenuClickEvent.java
  12. 4 4
      app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java
  13. 8 8
      app/src/main/java/com/nextcloud/talk/models/json/converters/EnumRoomTypeConverter.java
  14. 2 2
      app/src/main/java/com/nextcloud/talk/models/json/participants/AddParticipantOCS.java
  15. 1 1
      app/src/main/java/com/nextcloud/talk/models/json/rooms/Conversation.java
  16. 1 1
      app/src/main/java/com/nextcloud/talk/models/json/rooms/RoomOCS.java
  17. 1 1
      app/src/main/java/com/nextcloud/talk/models/json/rooms/RoomsOCS.java
  18. 4 4
      app/src/main/java/com/nextcloud/talk/utils/ShareUtils.java
  19. 31 0
      app/src/main/res/drawable/bubble_circle_unread.xml
  20. 31 0
      app/src/main/res/drawable/bubble_circle_unread_mention.xml
  21. 13 0
      app/src/main/res/drawable/shape_bubble_offline.xml
  22. 13 0
      app/src/main/res/drawable/shape_bubble_online.xml
  23. 119 0
      app/src/main/res/layout/rv_item_conversation_with_last_message.xml
  24. 1 1
      app/src/main/res/values-cs-rCZ/strings.xml
  25. 1 1
      app/src/main/res/values-de-rDE/strings.xml
  26. 1 1
      app/src/main/res/values-de/strings.xml
  27. 1 1
      app/src/main/res/values-es/strings.xml
  28. 1 1
      app/src/main/res/values-fr/strings.xml
  29. 1 1
      app/src/main/res/values-hu-rHU/strings.xml
  30. 1 1
      app/src/main/res/values-is/strings.xml
  31. 1 1
      app/src/main/res/values-it/strings.xml
  32. 1 1
      app/src/main/res/values-iw/strings.xml
  33. 1 1
      app/src/main/res/values-pt-rBR/strings.xml
  34. 1 1
      app/src/main/res/values-ru/strings.xml
  35. 1 1
      app/src/main/res/values-sk-rSK/strings.xml
  36. 1 1
      app/src/main/res/values-sr/strings.xml
  37. 1 1
      app/src/main/res/values-tr/strings.xml
  38. 1 1
      app/src/main/res/values-vi/strings.xml
  39. 1 1
      app/src/main/res/values-zh-rCN/strings.xml
  40. 3 1
      app/src/main/res/values/strings.xml

+ 22 - 25
app/src/main/java/com/nextcloud/talk/adapters/items/CallItem.java

@@ -37,7 +37,7 @@ import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.events.MoreMenuClickEvent;
 import com.nextcloud.talk.models.database.UserEntity;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.glide.GlideApp;
 
@@ -57,11 +57,11 @@ import eu.davidea.viewholders.FlexibleViewHolder;
 
 public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements IFilterable<String> {
 
-    private Room room;
+    private Conversation conversation;
     private UserEntity userEntity;
 
-    public CallItem(Room room, UserEntity userEntity) {
-        this.room = room;
+    public CallItem(Conversation conversation, UserEntity userEntity) {
+        this.conversation = conversation;
         this.userEntity = userEntity;
     }
 
@@ -69,22 +69,22 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
     public boolean equals(Object o) {
         if (o instanceof CallItem) {
             CallItem inItem = (CallItem) o;
-            return room.equals(inItem.getModel());
+            return conversation.equals(inItem.getModel());
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return room.hashCode();
+        return conversation.hashCode();
     }
 
     /**
      * @return the model object
      */
 
-    public Room getModel() {
-        return room;
+    public Conversation getModel() {
+        return conversation;
     }
 
     /**
@@ -104,21 +104,21 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
     @Override
     public void bindViewHolder(final FlexibleAdapter adapter, RoomItemViewHolder holder, int position, List payloads) {
         if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(holder.roomDisplayName, room.getDisplayName(),
+            FlexibleUtils.highlightText(holder.roomDisplayName, conversation.getDisplayName(),
                     String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.getSharedApplication()
                             .getResources().getColor(R.color.colorPrimary));
         } else {
-            holder.roomDisplayName.setText(room.getDisplayName());
+            holder.roomDisplayName.setText(conversation.getDisplayName());
         }
 
-        if (room.getLastPing() == 0) {
+        if (conversation.getLastPing() == 0) {
             holder.roomLastPing.setText(R.string.nc_never);
         } else {
-            holder.roomLastPing.setText(DateUtils.getRelativeTimeSpanString(room.getLastPing() * 1000L,
+            holder.roomLastPing.setText(DateUtils.getRelativeTimeSpanString(conversation.getLastPing() * 1000L,
                     System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
         }
 
-        if (room.hasPassword) {
+        if (conversation.hasPassword) {
             holder.passwordProtectedImageView.setVisibility(View.VISIBLE);
         } else {
             holder.passwordProtectedImageView.setVisibility(View.GONE);
@@ -128,16 +128,16 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
                 .getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
 
         Resources resources = NextcloudTalkApplication.getSharedApplication().getResources();
-        switch (room.getType()) {
+        switch (conversation.getType()) {
             case ROOM_TYPE_ONE_TO_ONE_CALL:
                 holder.avatarImageView.setVisibility(View.VISIBLE);
 
                 holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
-                        .nc_description_more_menu_one_to_one), room.getDisplayName()));
+                        .nc_description_more_menu_one_to_one), conversation.getDisplayName()));
 
-                if (!TextUtils.isEmpty(room.getName())) {
+                if (!TextUtils.isEmpty(conversation.getName())) {
                     GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
-                            room.getName(), R.dimen.avatar_size), new LazyHeaders.Builder()
+                            conversation.getName(), R.dimen.avatar_size), new LazyHeaders.Builder()
                             .setHeader("Accept", "image/*")
                             .setHeader("User-Agent", ApiUtils.getUserAgent())
                             .build());
@@ -157,7 +157,7 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
                 break;
             case ROOM_GROUP_CALL:
                 holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
-                        .nc_description_more_menu_group), room.getDisplayName()));
+                        .nc_description_more_menu_group), conversation.getDisplayName()));
 
                 GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
                         .asBitmap()
@@ -171,7 +171,7 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
                 break;
             case ROOM_PUBLIC_CALL:
                 holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
-                        .nc_description_more_menu_public), room.getDisplayName()));
+                        .nc_description_more_menu_public), conversation.getDisplayName()));
 
                 GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
                         .asBitmap()
@@ -188,13 +188,13 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
 
         }
 
-        holder.moreMenuButton.setOnClickListener(view -> EventBus.getDefault().post(new MoreMenuClickEvent(room)));
+        holder.moreMenuButton.setOnClickListener(view -> EventBus.getDefault().post(new MoreMenuClickEvent(conversation)));
     }
 
     @Override
     public boolean filter(String constraint) {
-        return room.getDisplayName() != null &&
-                StringUtils.containsIgnoreCase(room.getDisplayName().trim(), constraint);
+        return conversation.getDisplayName() != null &&
+                StringUtils.containsIgnoreCase(conversation.getDisplayName().trim(), constraint);
 
     }
 
@@ -211,9 +211,6 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
         @BindView(R.id.password_protected_image_view)
         ImageView passwordProtectedImageView;
 
-        /**
-         * Default constructor.
-         */
         RoomItemViewHolder(View view, FlexibleAdapter adapter) {
             super(view, adapter);
             ButterKnife.bind(this, view);

+ 292 - 0
app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java

@@ -0,0 +1,292 @@
+/*
+ * 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.items;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.text.style.StyleSpan;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.amulyakhare.textdrawable.TextDrawable;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.load.model.LazyHeaders;
+import com.bumptech.glide.load.resource.bitmap.CircleCrop;
+import com.bumptech.glide.request.RequestOptions;
+import com.nextcloud.talk.R;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.models.json.rooms.Conversation;
+import com.nextcloud.talk.utils.ApiUtils;
+import com.nextcloud.talk.utils.glide.GlideApp;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import eu.davidea.flexibleadapter.FlexibleAdapter;
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
+import eu.davidea.flexibleadapter.items.IFilterable;
+import eu.davidea.flexibleadapter.items.IFlexible;
+import eu.davidea.flexibleadapter.utils.FlexibleUtils;
+import eu.davidea.viewholders.FlexibleViewHolder;
+
+public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements
+        IFilterable<String> {
+
+
+    private Conversation conversation;
+    private UserEntity userEntity;
+
+    public ConversationItem(Conversation conversation, UserEntity userEntity) {
+        this.conversation = conversation;
+        this.userEntity = userEntity;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof ConversationItem) {
+            ConversationItem inItem = (ConversationItem) o;
+            return conversation.equals(inItem.getModel());
+        }
+        return false;
+    }
+
+    public Conversation getModel() {
+        return conversation;
+    }
+
+    @Override
+    public int hashCode() {
+        return conversation.hashCode();
+    }
+
+    @Override
+    public int getLayoutRes() {
+        return R.layout.rv_item_conversation_with_last_message;
+    }
+
+    @Override
+    public ConversationItemViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
+        return new ConversationItemViewHolder(view, adapter);
+    }
+
+    @Override
+    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ConversationItemViewHolder holder, int position, List<Object> payloads) {
+        Context context = NextcloudTalkApplication.getSharedApplication().getApplicationContext();
+        if (adapter.hasFilter()) {
+            FlexibleUtils.highlightText(holder.dialogName, conversation.getDisplayName(),
+                    String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.getSharedApplication()
+                            .getResources().getColor(R.color.colorPrimary));
+        } else {
+            holder.dialogName.setText(conversation.getDisplayName());
+        }
+
+        if (conversation.getUnreadMessages() > 0) {
+            holder.dialogUnreadBubble.setVisibility(View.VISIBLE);
+            if (conversation.getUnreadMessages() < 10) {
+                holder.dialogUnreadBubble.setText(Long.toString(conversation.getUnreadMessages()));
+            } else {
+                holder.dialogUnreadBubble.setText("+");
+            }
+
+            if (conversation.isUnreadMention()) {
+                holder.dialogUnreadBubble.setBackground(context.getDrawable(R.drawable.bubble_circle_unread_mention));
+            } else {
+                holder.dialogUnreadBubble.setBackground(context.getDrawable(R.drawable.bubble_circle_unread));
+            }
+        } else {
+            holder.dialogUnreadBubble.setVisibility(View.GONE);
+        }
+
+        String authorDisplayName = "";
+
+        if (conversation.getLastMessage() != null) {
+            holder.dialogDate.setVisibility(View.VISIBLE);
+            holder.dialogDate.setText(DateUtils.getRelativeTimeSpanString(conversation.getLastActivity() * 1000L,
+                    System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
+
+            if (conversation.getType() == Conversation.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL) {
+                holder.dialogLastMessageUserAvatar.setVisibility(View.GONE);
+                holder.dialogLastMessage.setText(conversation.getLastMessage().getText());
+            } else {
+                holder.dialogLastMessageUserAvatar.setVisibility(View.VISIBLE);
+                if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())) {
+                    authorDisplayName = context.getString(R.string.nc_chat_you) + ": ";
+                } else {
+                    if (!TextUtils.isEmpty(conversation.getLastMessage().getActorDisplayName())) {
+                        authorDisplayName = conversation.getLastMessage().getActorDisplayName() + ": ";
+                    } else {
+                        authorDisplayName = context.getString(R.string.nc_nick_guest) + ": ";
+                    }
+                }
+
+                String fullString = authorDisplayName + conversation.getLastMessage().getText();
+                Spannable spannableString = new SpannableString(fullString);
+                final StyleSpan boldStyleSpan = new StyleSpan(Typeface.BOLD);
+                spannableString.setSpan(boldStyleSpan, 0, fullString.indexOf(":") + 1, Spannable
+                        .SPAN_INCLUSIVE_INCLUSIVE);
+
+                holder.dialogLastMessage.setText(spannableString, TextView.BufferType.SPANNABLE);
+                holder.dialogLastMessageUserAvatar.setVisibility(View.VISIBLE);
+
+                int smallAvatarSize = Math.round(context.getResources().getDimension(R.dimen.small_item_height));
+
+                if (conversation.getLastMessage().getActorType().equals("guests")) {
+                    TextDrawable drawable = TextDrawable.builder().beginConfig().bold()
+                            .endConfig().buildRound(String.valueOf(authorDisplayName.charAt(0)),
+                                    context.getResources().getColor(R.color.nc_grey));
+                    holder.dialogLastMessageUserAvatar.setImageDrawable(drawable);
+                } else {
+                    GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                            conversation.getLastMessage().getActorId(), R.dimen.small_item_height), new LazyHeaders.Builder()
+                            .setHeader("Accept", "image/*")
+                            .setHeader("User-Agent", ApiUtils.getUserAgent())
+                            .build());
+
+                    GlideApp.with(context)
+                            .asBitmap()
+                            .diskCacheStrategy(DiskCacheStrategy.NONE)
+                            .load(glideUrl)
+                            .centerInside()
+                            .override(smallAvatarSize, smallAvatarSize)
+                            .apply(RequestOptions.bitmapTransform(new CircleCrop()))
+                            .into(holder.dialogLastMessageUserAvatar);
+                }
+            }
+
+        } else {
+            holder.dialogDate.setVisibility(View.GONE);
+            holder.dialogLastMessageUserAvatar.setVisibility(View.GONE);
+            holder.dialogLastMessage.setText(R.string.nc_no_messages_yet);
+        }
+
+        int avatarSize = Math.round(context.getResources().getDimension(R.dimen.avatar_size));
+
+
+        holder.dialogAvatar.setVisibility(View.VISIBLE);
+
+        switch (conversation.getType()) {
+            case ROOM_TYPE_ONE_TO_ONE_CALL:
+                holder.onlineIndicator.setVisibility(View.VISIBLE);
+
+                if (conversation.getParticipants() == null || conversation.getParticipants().isEmpty()) {
+                    holder.onlineIndicator.setBackground(context.getDrawable(R.drawable.shape_bubble_offline));
+                } else {
+                    holder.onlineIndicator.setBackground(context.getDrawable(R.drawable.shape_bubble_online));
+                }
+
+                //holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
+                //        .nc_description_more_menu_one_to_one), conversation.getDisplayName()));
+
+                if (!TextUtils.isEmpty(conversation.getName())) {
+                    GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                            conversation.getName(), R.dimen.avatar_size), new LazyHeaders.Builder()
+                            .setHeader("Accept", "image/*")
+                            .setHeader("User-Agent", ApiUtils.getUserAgent())
+                            .build());
+
+                    GlideApp.with(context)
+                            .asBitmap()
+                            .diskCacheStrategy(DiskCacheStrategy.NONE)
+                            .load(glideUrl)
+                            .centerInside()
+                            .override(avatarSize, avatarSize)
+                            .apply(RequestOptions.bitmapTransform(new CircleCrop()))
+                            .into(holder.dialogAvatar);
+
+                } else {
+                    holder.dialogAvatar.setVisibility(View.GONE);
+                }
+                break;
+            case ROOM_GROUP_CALL:
+                //holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
+                //        .nc_description_more_menu_group), conversation.getDisplayName()));
+
+                holder.onlineIndicator.setVisibility(View.GONE);
+
+                GlideApp.with(context)
+                        .asBitmap()
+                        .diskCacheStrategy(DiskCacheStrategy.NONE)
+                        .load(R.drawable.ic_group_white_24px)
+                        .centerInside()
+                        .override(avatarSize, avatarSize)
+                        .apply(RequestOptions.bitmapTransform(new CircleCrop()))
+                        .into(holder.dialogAvatar);
+                break;
+            case ROOM_PUBLIC_CALL:
+                //holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
+                //        .nc_description_more_menu_public), conversation.getDisplayName()));
+                holder.onlineIndicator.setVisibility(View.GONE);
+                GlideApp.with(context)
+                        .asBitmap()
+                        .diskCacheStrategy(DiskCacheStrategy.NONE)
+                        .load(R.drawable.ic_link_white_24px)
+                        .centerInside()
+                        .override(avatarSize, avatarSize)
+                        .apply(RequestOptions.bitmapTransform(new CircleCrop()))
+                        .into(holder.dialogAvatar);
+
+                break;
+            default:
+                holder.onlineIndicator.setVisibility(View.GONE);
+                holder.dialogAvatar.setVisibility(View.GONE);
+        }
+
+
+    }
+
+    @Override
+    public boolean filter(String constraint) {
+        return conversation.getDisplayName() != null &&
+                StringUtils.containsIgnoreCase(conversation.getDisplayName().trim(), constraint);
+    }
+
+    static class ConversationItemViewHolder extends FlexibleViewHolder {
+        @BindView(R.id.dialogAvatar)
+        ImageView dialogAvatar;
+        @BindView(R.id.dialogName)
+        TextView dialogName;
+        @BindView(R.id.dialogDate)
+        TextView dialogDate;
+        @BindView(R.id.dialogLastMessageUserAvatar)
+        ImageView dialogLastMessageUserAvatar;
+        @BindView(R.id.dialogLastMessage)
+        TextView dialogLastMessage;
+        @BindView(R.id.dialogUnreadBubble)
+        TextView dialogUnreadBubble;
+        @BindView(R.id.onlineIndicator)
+        ImageView onlineIndicator;
+
+        ConversationItemViewHolder(View view, FlexibleAdapter adapter) {
+            super(view, adapter);
+            ButterKnife.bind(this, view);
+        }
+    }
+}

+ 4 - 4
app/src/main/java/com/nextcloud/talk/controllers/CallController.java

@@ -61,7 +61,7 @@ import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
 import com.nextcloud.talk.models.json.generic.GenericOverall;
 import com.nextcloud.talk.models.json.participants.Participant;
 import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.models.json.rooms.RoomsOverall;
 import com.nextcloud.talk.models.json.signaling.DataChannelMessage;
 import com.nextcloud.talk.models.json.signaling.NCIceCandidate;
@@ -382,9 +382,9 @@ public class CallController extends BaseController {
 
                     @Override
                     public void onNext(RoomsOverall roomsOverall) {
-                        for (Room room : roomsOverall.getOcs().getData()) {
-                            if (roomId.equals(room.getRoomId())) {
-                                roomToken = room.getToken();
+                        for (Conversation conversation : roomsOverall.getOcs().getData()) {
+                            if (roomId.equals(conversation.getRoomId())) {
+                                roomToken = conversation.getToken();
                                 break;
                             }
                         }

+ 12 - 12
app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java

@@ -68,7 +68,7 @@ import com.nextcloud.talk.models.RingtoneSettings;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.participants.Participant;
 import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.models.json.rooms.RoomsOverall;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DoNotDisturbUtils;
@@ -138,7 +138,7 @@ public class CallNotificationController extends BaseController {
     private String roomId;
     private UserEntity userBeingCalled;
     private String credentials;
-    private Room currentRoom;
+    private Conversation currentConversation;
     private MediaPlayer mediaPlayer;
     private boolean leavingScreen = false;
     private RenderScript renderScript;
@@ -150,7 +150,7 @@ public class CallNotificationController extends BaseController {
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
 
         this.roomId = args.getString(BundleKeys.KEY_ROOM_ID, "");
-        this.currentRoom = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
+        this.currentConversation = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
         this.userBeingCalled = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_USER_ENTITY));
 
         this.originalBundle = args;
@@ -190,7 +190,7 @@ public class CallNotificationController extends BaseController {
     }
 
     private void proceedToCall() {
-        originalBundle.putString(BundleKeys.KEY_ROOM_TOKEN, currentRoom.getToken());
+        originalBundle.putString(BundleKeys.KEY_ROOM_TOKEN, currentConversation.getToken());
 
         getRouter().setRoot(RouterTransaction.with(new CallController(originalBundle))
                 .popChangeHandler(new HorizontalChangeHandler())
@@ -199,7 +199,7 @@ public class CallNotificationController extends BaseController {
 
     private void checkIfAnyParticipantsRemainInRoom() {
         ncApi.getPeersForCall(credentials, ApiUtils.getUrlForParticipants(userBeingCalled.getBaseUrl(),
-                currentRoom.getToken()))
+                currentConversation.getToken()))
                 .subscribeOn(Schedulers.newThread())
                 .takeWhile(observable -> !leavingScreen)
                 .retry(3)
@@ -260,9 +260,9 @@ public class CallNotificationController extends BaseController {
 
                     @Override
                     public void onNext(RoomsOverall roomsOverall) {
-                        for (Room room : roomsOverall.getOcs().getData()) {
-                            if (roomId.equals(room.getRoomId())) {
-                                currentRoom = room;
+                        for (Conversation conversation : roomsOverall.getOcs().getData()) {
+                            if (roomId.equals(conversation.getRoomId())) {
+                                currentConversation = conversation;
                                 runAllThings();
                                 break;
                             }
@@ -284,7 +284,7 @@ public class CallNotificationController extends BaseController {
 
     private void runAllThings() {
         if (conversationNameTextView != null) {
-            conversationNameTextView.setText(currentRoom.getDisplayName());
+            conversationNameTextView.setText(currentConversation.getDisplayName());
         }
 
         loadAvatar();
@@ -305,7 +305,7 @@ public class CallNotificationController extends BaseController {
             Log.e(TAG, "Failed to evict cache");
         }
 
-        if (currentRoom == null) {
+        if (currentConversation == null) {
             handleFromNotification();
         } else {
             runAllThings();
@@ -396,12 +396,12 @@ public class CallNotificationController extends BaseController {
         int avatarSize = Math.round(NextcloudTalkApplication
                 .getSharedApplication().getResources().getDimension(R.dimen.avatar_fetching_size_very_big));
 
-        switch (currentRoom.getType()) {
+        switch (currentConversation.getType()) {
             case ROOM_TYPE_ONE_TO_ONE_CALL:
                 avatarImageView.setVisibility(View.VISIBLE);
 
                 GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
-                        currentRoom.getName(), R.dimen.avatar_size_very_big), new LazyHeaders.Builder()
+                        currentConversation.getName(), R.dimen.avatar_size_very_big), new LazyHeaders.Builder()
                         .setHeader("Accept", "image/*")
                         .setHeader("User-Agent", ApiUtils.getUserAgent())
                         .build());

+ 46 - 22
app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java

@@ -52,6 +52,7 @@ import com.kennyc.bottomsheet.BottomSheet;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.activities.MagicCallActivity;
 import com.nextcloud.talk.adapters.items.CallItem;
+import com.nextcloud.talk.adapters.items.ConversationItem;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
@@ -61,7 +62,7 @@ import com.nextcloud.talk.events.BottomSheetLockEvent;
 import com.nextcloud.talk.events.MoreMenuClickEvent;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.participants.Participant;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.KeyboardUtils;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
@@ -84,6 +85,7 @@ import butterknife.BindView;
 import eu.davidea.fastscroller.FastScroller;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.Disposable;
 import io.reactivex.schedulers.Schedulers;
@@ -116,8 +118,8 @@ public class CallsListController extends BaseController implements SearchView.On
 
     private UserEntity currentUser;
     private Disposable roomsQueryDisposable;
-    private FlexibleAdapter<CallItem> adapter;
-    private List<CallItem> callItems = new ArrayList<>();
+    private FlexibleAdapter<AbstractFlexibleItem> adapter;
+    private List<AbstractFlexibleItem> callItems = new ArrayList<>();
 
     private BottomSheet bottomSheet;
     private MenuItem searchItem;
@@ -125,6 +127,7 @@ public class CallsListController extends BaseController implements SearchView.On
     private String searchQuery;
 
     private View view;
+    private boolean shouldUseLastMessageLayout;
 
     public CallsListController() {
         super();
@@ -154,9 +157,11 @@ public class CallsListController extends BaseController implements SearchView.On
                     .popChangeHandler(new HorizontalChangeHandler())));
         }
 
+
         if (adapter == null) {
             adapter = new FlexibleAdapter<>(callItems, getActivity(), false);
             if (currentUser != null) {
+                shouldUseLastMessageLayout = currentUser.hasSpreedCapabilityWithName("last-room-activity");
                 fetchData(false);
             }
         }
@@ -276,25 +281,32 @@ public class CallsListController extends BaseController implements SearchView.On
 
                     if (roomsOverall != null) {
                         for (int i = 0; i < roomsOverall.getOcs().getData().size(); i++) {
-                            callItems.add(new CallItem(roomsOverall.getOcs().getData().get(i), currentUser));
+                            if (shouldUseLastMessageLayout) {
+                                callItems.add(new ConversationItem(roomsOverall.getOcs().getData().get(i),
+                                        currentUser));
+                            } else {
+                                callItems.add(new CallItem(roomsOverall.getOcs().getData().get(i), currentUser));
+                            }
                         }
 
-                        adapter.updateDataSet(callItems, true);
 
                         if (currentUser.hasSpreedCapabilityWithName("last-room-activity")) {
                             Collections.sort(callItems, (o1, o2) -> {
-                                Room room1 = o1.getModel();
-                                Room room2 = o2.getModel();
+                                Conversation conversation1 = ((ConversationItem) o1).getModel();
+                                Conversation conversation2 = ((ConversationItem) o2).getModel();
                                 return new CompareToBuilder()
-                                        .append(room1.isPinned(), room2.isPinned())
-                                        .append(room1.getLastActivity(), room2.getLastActivity())
+                                        .append(conversation2.isPinned(), conversation1.isPinned())
+                                        .append(conversation2.getLastActivity(), conversation1.getLastActivity())
                                         .toComparison();
                             });
                         } else {
                             Collections.sort(callItems, (callItem, t1) ->
-                                    Long.compare(t1.getModel().getLastPing(), callItem.getModel().getLastPing()));
+                                    Long.compare(((CallItem) t1).getModel().getLastPing(),
+                                            ((CallItem) callItem).getModel().getLastPing()));
                         }
 
+                        adapter.updateDataSet(callItems, true);
+
                         if (searchItem != null) {
                             searchItem.setVisible(callItems.size() > 0);
                         }
@@ -368,7 +380,13 @@ public class CallsListController extends BaseController implements SearchView.On
         fastScroller.addOnScrollStateChangeListener(this);
         adapter.setFastScroller(fastScroller);
         fastScroller.setBubbleTextCreator(position -> {
-            String displayName = adapter.getItem(position).getModel().getDisplayName();
+            String displayName;
+            if (shouldUseLastMessageLayout) {
+                displayName = ((ConversationItem)adapter.getItem(position)).getModel().getDisplayName();
+            } else {
+                displayName = ((CallItem)adapter.getItem(position)).getModel().getDisplayName();
+            }
+
             if (displayName.length() > 8) {
                 displayName = displayName.substring(0, 4) + "...";
             }
@@ -455,8 +473,8 @@ public class CallsListController extends BaseController implements SearchView.On
     @Subscribe(threadMode = ThreadMode.MAIN)
     public void onMessageEvent(MoreMenuClickEvent moreMenuClickEvent) {
         Bundle bundle = new Bundle();
-        Room room = moreMenuClickEvent.getRoom();
-        bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room));
+        Conversation conversation = moreMenuClickEvent.getConversation();
+        bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
         bundle.putParcelable(BundleKeys.KEY_MENU_TYPE, Parcels.wrap(CallMenuController.MenuType.REGULAR));
 
         prepareAndShowBottomSheetWithBundle(bundle, true);
@@ -500,23 +518,29 @@ public class CallsListController extends BaseController implements SearchView.On
 
     @Override
     public boolean onItemClick(View view, int position) {
-        CallItem callItem = adapter.getItem(position);
-        if (callItem != null && getActivity() != null) {
-            Room room = callItem.getModel();
+        Object clickedItem = adapter.getItem(position);
+        if (clickedItem != null && getActivity() != null) {
+            Conversation conversation;
+            if (shouldUseLastMessageLayout) {
+                conversation = ((ConversationItem)clickedItem).getModel();
+            } else {
+                conversation = ((CallItem)clickedItem).getModel();
+            }
+
             Bundle bundle = new Bundle();
-            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, callItem.getModel().getToken());
-            bundle.putString(BundleKeys.KEY_ROOM_ID, callItem.getModel().getRoomId());
-            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, callItem.getModel().getToken());
+            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation.getToken());
+            bundle.putString(BundleKeys.KEY_ROOM_ID, conversation.getRoomId());
+            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation.getToken());
 
-            if (room.hasPassword && (room.participantType.equals(Participant.ParticipantType.GUEST) ||
-                    room.participantType.equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
+            if (conversation.hasPassword && (conversation.participantType.equals(Participant.ParticipantType.GUEST) ||
+                    conversation.participantType.equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
                 bundle.putInt(BundleKeys.KEY_OPERATION_CODE, 99);
                 prepareAndShowBottomSheetWithBundle(bundle, false);
             } else {
                 currentUser = userUtils.getCurrentUser();
 
                 if (currentUser.hasSpreedCapabilityWithName("chat-v2")) {
-                    bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, room.getDisplayName());
+                    bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, conversation.getDisplayName());
                     getParentController().getRouter().pushController((RouterTransaction.with(new ChatController(bundle))
                             .pushChangeHandler(new HorizontalChangeHandler())
                             .popChangeHandler(new HorizontalChangeHandler())));

+ 5 - 5
app/src/main/java/com/nextcloud/talk/controllers/ChatController.java

@@ -73,7 +73,7 @@ import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.models.json.chat.ChatOverall;
 import com.nextcloud.talk.models.json.generic.GenericOverall;
 import com.nextcloud.talk.models.json.mention.Mention;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.models.json.rooms.RoomOverall;
 import com.nextcloud.talk.models.json.rooms.RoomsOverall;
 import com.nextcloud.talk.presenters.MentionAutocompletePresenter;
@@ -262,10 +262,10 @@ public class ChatController extends BaseController implements MessagesListAdapte
 
                     @Override
                     public void onNext(RoomsOverall roomsOverall) {
-                        for (Room room : roomsOverall.getOcs().getData()) {
-                            if (roomId.equals(room.getRoomId())) {
-                                roomToken = room.getToken();
-                                conversationName = room.getDisplayName();
+                        for (Conversation conversation : roomsOverall.getOcs().getData()) {
+                            if (roomId.equals(conversation.getRoomId())) {
+                                roomToken = conversation.getToken();
+                                conversationName = conversation.getDisplayName();
                                 setTitle();
                                 break;
                             }

+ 4 - 4
app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java

@@ -61,7 +61,7 @@ import com.nextcloud.talk.events.BottomSheetLockEvent;
 import com.nextcloud.talk.models.RetrofitBucket;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.participants.Participant;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.models.json.rooms.RoomOverall;
 import com.nextcloud.talk.models.json.sharees.Sharee;
 import com.nextcloud.talk.models.json.sharees.ShareesOverall;
@@ -296,11 +296,11 @@ public class ContactsController extends BaseController implements SearchView.OnQ
         } else {
 
             Bundle bundle = new Bundle();
-            Room.RoomType roomType;
+            Conversation.RoomType roomType;
             if (isPublicCall) {
-                roomType = Room.RoomType.ROOM_PUBLIC_CALL;
+                roomType = Conversation.RoomType.ROOM_PUBLIC_CALL;
             } else {
-                roomType = Room.RoomType.ROOM_GROUP_CALL;
+                roomType = Conversation.RoomType.ROOM_GROUP_CALL;
             }
 
             bundle.putParcelable(BundleKeys.KEY_CONVERSATION_TYPE, Parcels.wrap(roomType));

+ 18 - 18
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java

@@ -42,7 +42,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.ContactsController;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.events.BottomSheetLockEvent;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.utils.ShareUtils;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
@@ -73,7 +73,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
     @Inject
     UserUtils userUtils;
 
-    private Room room;
+    private Conversation conversation;
     private List<AbstractFlexibleItem> menuItems;
     private FlexibleAdapter<AbstractFlexibleItem> adapter;
     private MenuType menuType;
@@ -81,7 +81,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
 
     public CallMenuController(Bundle args) {
         super(args);
-        this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
+        this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
         if (args.containsKey(BundleKeys.KEY_MENU_TYPE)) {
             this.menuType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_MENU_TYPE));
         }
@@ -124,25 +124,25 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
         menuItems = new ArrayList<>();
 
         if (menuType.equals(MenuType.REGULAR)) {
-            if (!TextUtils.isEmpty(room.getDisplayName())) {
-                menuItems.add(new MenuItem(room.getDisplayName(), 0, null));
-            } else if (!TextUtils.isEmpty(room.getName())) {
-                menuItems.add(new MenuItem(room.getName(), 0, null));
+            if (!TextUtils.isEmpty(conversation.getDisplayName())) {
+                menuItems.add(new MenuItem(conversation.getDisplayName(), 0, null));
+            } else if (!TextUtils.isEmpty(conversation.getName())) {
+                menuItems.add(new MenuItem(conversation.getName(), 0, null));
             } else {
                 menuItems.add(new MenuItem(getResources().getString(R.string.nc_configure_room), 0, null));
             }
 
-            if (room.isNameEditable()) {
+            if (conversation.isNameEditable()) {
                 menuItems.add(new MenuItem(getResources().getString(R.string.nc_rename), 2, getResources().getDrawable(R.drawable
                         .ic_pencil_grey600_24dp)));
             }
 
-            if (room.canModerate()) {
-                if (!room.isPublic()) {
+            if (conversation.canModerate()) {
+                if (!conversation.isPublic()) {
                     menuItems.add(new MenuItem(getResources().getString(R.string.nc_make_call_public), 3, getResources().getDrawable(R.drawable
                             .ic_link_grey600_24px)));
                 } else {
-                    if (room.isHasPassword()) {
+                    if (conversation.isHasPassword()) {
                         menuItems.add(new MenuItem(getResources().getString(R.string.nc_change_password), 4, getResources().getDrawable(R.drawable
                                 .ic_lock_grey600_24px)));
                         menuItems.add(new MenuItem(getResources().getString(R.string.nc_clear_password), 5, getResources().getDrawable(R.drawable
@@ -154,16 +154,16 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
                 }
             }
 
-            if (room.isPublic()) {
+            if (conversation.isPublic()) {
                 menuItems.add(new MenuItem(getResources().getString(R.string.nc_share_link), 7, getResources().getDrawable(R.drawable
                         .ic_link_grey600_24px)));
-                if (room.canModerate()) {
+                if (conversation.canModerate()) {
                     menuItems.add(new MenuItem(getResources().getString(R.string.nc_make_call_private), 8, getResources().getDrawable(R.drawable
                             .ic_group_grey600_24px)));
                 }
             }
 
-            if (room.isDeletable()) {
+            if (conversation.isDeletable()) {
                 menuItems.add(new MenuItem(getResources().getString(R.string.nc_delete_call), 9, getResources().getDrawable(R.drawable
                         .ic_delete_grey600_24dp)));
             }
@@ -191,7 +191,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
     @Override
     public boolean onItemClick(View view, int position) {
         Bundle bundle = new Bundle();
-        bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room));
+        bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
 
         if (menuType.equals(MenuType.REGULAR)) {
             MenuItem menuItem = (MenuItem) adapter.getItem(position);
@@ -199,7 +199,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
 
                 int tag = menuItem.getTag();
                 if (tag == 5) {
-                    room.setPassword("");
+                    conversation.setPassword("");
                 }
 
                 if (tag > 0 && tag < 10) {
@@ -224,9 +224,9 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
         } else if (menuType.equals(MenuType.SHARE) && position != 0) {
             AppItem appItem = (AppItem) adapter.getItem(position);
             if (appItem != null && getActivity() != null) {
-                if (!room.hasPassword) {
+                if (!conversation.hasPassword) {
                     shareIntent.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(getActivity(), null,
-                            userUtils, room));
+                            userUtils, conversation));
                     Intent intent = new Intent(shareIntent);
                     intent.setComponent(new ComponentName(appItem.getPackageName(), appItem.getName()));
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

+ 12 - 12
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java

@@ -40,7 +40,7 @@ import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.events.BottomSheetLockEvent;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
 import com.nextcloud.talk.utils.ShareUtils;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
@@ -76,7 +76,7 @@ public class EntryMenuController extends BaseController {
     UserUtils userUtils;
 
     private int operationCode;
-    private Room room;
+    private Conversation conversation;
     private Intent shareIntent;
     private String packageName;
     private String name;
@@ -90,7 +90,7 @@ public class EntryMenuController extends BaseController {
 
         this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE);
         if (args.containsKey(BundleKeys.KEY_ROOM)) {
-            this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
+            this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
         }
 
         if (args.containsKey(BundleKeys.KEY_SHARE_INTENT)) {
@@ -127,7 +127,7 @@ public class EntryMenuController extends BaseController {
         if (operationCode == 99) {
             eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
             bundle = new Bundle();
-            bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room));
+            bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
             bundle.putString(BundleKeys.KEY_CALL_URL, callUrl);
             bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, editText.getText().toString());
             bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode);
@@ -141,11 +141,11 @@ public class EntryMenuController extends BaseController {
             eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
             bundle = new Bundle();
             if (operationCode == 4 || operationCode == 6) {
-                room.setPassword(editText.getText().toString());
+                conversation.setPassword(editText.getText().toString());
             } else {
-                room.setName(editText.getText().toString());
+                conversation.setName(editText.getText().toString());
             }
-            bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room));
+            bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
             bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode);
             getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))
                     .pushChangeHandler(new HorizontalChangeHandler())
@@ -153,7 +153,7 @@ public class EntryMenuController extends BaseController {
         } else if (operationCode == 7) {
             if (getActivity() != null) {
                 shareIntent.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(getActivity(),
-                        editText.getText().toString(), userUtils, room));
+                        editText.getText().toString(), userUtils, conversation));
                 Intent intent = new Intent(shareIntent);
                 intent.setComponent(new ComponentName(packageName, name));
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -184,8 +184,8 @@ public class EntryMenuController extends BaseController {
         super.onViewBound(view);
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
 
-        if (room != null && operationCode == 2) {
-            editText.setText(room.getName());
+        if (conversation != null && operationCode == 2) {
+            editText.setText(conversation.getName());
         }
 
         editText.setOnEditorActionListener((v, actionId, event) -> {
@@ -211,7 +211,7 @@ public class EntryMenuController extends BaseController {
             public void afterTextChanged(Editable s) {
                 if (!TextUtils.isEmpty(s)) {
                     if (operationCode == 2) {
-                        if (room.getName() == null || !room.getName().equals(s.toString())) {
+                        if (conversation.getName() == null || !conversation.getName().equals(s.toString())) {
                             if (!proceedButton.isEnabled()) {
                                 proceedButton.setEnabled(true);
                                 proceedButton.setAlpha(1.0f);
@@ -269,7 +269,7 @@ public class EntryMenuController extends BaseController {
             case 6:
             case 7:
             case 99:
-                // 99 is joining a room via password
+                // 99 is joining a conversation via password
                 labelText = getResources().getString(R.string.nc_password);
                 editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
                 break;

+ 27 - 27
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java

@@ -53,7 +53,7 @@ import com.nextcloud.talk.models.json.call.CallOverall;
 import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
 import com.nextcloud.talk.models.json.generic.GenericOverall;
 import com.nextcloud.talk.models.json.participants.AddParticipantOverall;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.models.json.rooms.RoomOverall;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
@@ -105,7 +105,7 @@ public class OperationsMenuController extends BaseController {
     EventBus eventBus;
 
     private int operationCode;
-    private Room room;
+    private Conversation conversation;
 
     private UserEntity currentUser;
     private String callPassword;
@@ -117,7 +117,7 @@ public class OperationsMenuController extends BaseController {
 
     private Disposable disposable;
 
-    private Room.RoomType conversationType;
+    private Conversation.RoomType conversationType;
     private ArrayList<String> invitedUsers = new ArrayList<>();
 
     private List<String> spreedCapabilities;
@@ -127,7 +127,7 @@ public class OperationsMenuController extends BaseController {
         super(args);
         this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE);
         if (args.containsKey(BundleKeys.KEY_ROOM)) {
-            this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
+            this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
         }
 
         this.callPassword = args.getString(BundleKeys.KEY_CONVERSATION_PASSWORD, "");
@@ -182,22 +182,22 @@ public class OperationsMenuController extends BaseController {
             switch (operationCode) {
                 case 1:
                     ncApi.removeSelfFromRoom(credentials, ApiUtils.getUrlForRemoveSelfFromRoom(currentUser.getBaseUrl
-                            (), room.getToken()))
+                            (), conversation.getToken()))
                             .subscribeOn(Schedulers.newThread())
                             .observeOn(AndroidSchedulers.mainThread())
                             .retry(1)
                             .subscribe(operationsObserver);
                     break;
                 case 2:
-                    ncApi.renameRoom(credentials, ApiUtils.getRoom(currentUser.getBaseUrl(), room.getToken()),
-                            room.getName())
+                    ncApi.renameRoom(credentials, ApiUtils.getRoom(currentUser.getBaseUrl(), conversation.getToken()),
+                            conversation.getName())
                             .subscribeOn(Schedulers.newThread())
                             .observeOn(AndroidSchedulers.mainThread())
                             .retry(1)
                             .subscribe(operationsObserver);
                     break;
                 case 3:
-                    ncApi.makeRoomPublic(credentials, ApiUtils.getUrlForRoomVisibility(currentUser.getBaseUrl(), room
+                    ncApi.makeRoomPublic(credentials, ApiUtils.getUrlForRoomVisibility(currentUser.getBaseUrl(), conversation
                             .getToken()))
                             .subscribeOn(Schedulers.newThread())
                             .observeOn(AndroidSchedulers.mainThread())
@@ -208,11 +208,11 @@ public class OperationsMenuController extends BaseController {
                 case 5:
                 case 6:
                     String pass = "";
-                    if (room.getPassword() != null) {
-                        pass = room.getPassword();
+                    if (conversation.getPassword() != null) {
+                        pass = conversation.getPassword();
                     }
                     ncApi.setPassword(credentials, ApiUtils.getUrlForPassword(currentUser.getBaseUrl(),
-                            room.getToken()), pass)
+                            conversation.getToken()), pass)
                             .subscribeOn(Schedulers.newThread())
                             .observeOn(AndroidSchedulers.mainThread())
                             .retry(1)
@@ -222,7 +222,7 @@ public class OperationsMenuController extends BaseController {
                     // Operation 7 is sharing, so we handle this differently
                     break;
                 case 8:
-                    ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomVisibility(currentUser.getBaseUrl(), room
+                    ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomVisibility(currentUser.getBaseUrl(), conversation
                             .getToken()))
                             .subscribeOn(Schedulers.newThread())
                             .observeOn(AndroidSchedulers.mainThread())
@@ -230,7 +230,7 @@ public class OperationsMenuController extends BaseController {
                             .subscribe(operationsObserver);
                     break;
                 case 9:
-                    ncApi.deleteRoom(credentials, ApiUtils.getUrlForSettingMyselfAsActiveParticipant(currentUser.getBaseUrl(), room.getToken()))
+                    ncApi.deleteRoom(credentials, ApiUtils.getUrlForSettingMyselfAsActiveParticipant(currentUser.getBaseUrl(), conversation.getToken()))
                             .subscribeOn(Schedulers.newThread())
                             .observeOn(AndroidSchedulers.mainThread())
                             .retry(1)
@@ -249,7 +249,7 @@ public class OperationsMenuController extends BaseController {
 
                                 @Override
                                 public void onNext(RoomOverall roomOverall) {
-                                    room = roomOverall.getOcs().getData();
+                                    conversation = roomOverall.getOcs().getData();
                                     fetchCapabilities(credentials);
                                 }
 
@@ -268,13 +268,13 @@ public class OperationsMenuController extends BaseController {
                 case 11:
                     RetrofitBucket retrofitBucket;
                     boolean isGroupCallWorkaround = false;
-                    if (conversationType.equals(Room.RoomType.ROOM_PUBLIC_CALL) ||
-                            !currentUser.hasSpreedCapabilityWithName("empty-group-room")) {
+                    if (conversationType.equals(Conversation.RoomType.ROOM_PUBLIC_CALL) ||
+                            !currentUser.hasSpreedCapabilityWithName("empty-group-conversation")) {
                         retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(currentUser.getBaseUrl(),
                                 "3", null, null);
                     } else {
                         String roomType = "2";
-                        if (!currentUser.hasSpreedCapabilityWithName("empty-group-room")) {
+                        if (!currentUser.hasSpreedCapabilityWithName("empty-group-conversation")) {
                             isGroupCallWorkaround = true;
                             roomType = "3";
                         }
@@ -295,8 +295,8 @@ public class OperationsMenuController extends BaseController {
 
                                 @Override
                                 public void onNext(RoomOverall roomOverall) {
-                                    room = roomOverall.getOcs().getData();
-                                    if (conversationType.equals(Room.RoomType.ROOM_PUBLIC_CALL) && isGroupCallWorkaroundFinal) {
+                                    conversation = roomOverall.getOcs().getData();
+                                    if (conversationType.equals(Conversation.RoomType.ROOM_PUBLIC_CALL) && isGroupCallWorkaroundFinal) {
                                         performGroupCallWorkaround(credentials);
                                     } else {
                                         inviteUsersToAConversation();
@@ -331,7 +331,7 @@ public class OperationsMenuController extends BaseController {
     }
 
     private void performGroupCallWorkaround(String credentials) {
-        ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomVisibility(currentUser.getBaseUrl(), room.getToken()))
+        ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomVisibility(currentUser.getBaseUrl(), conversation.getToken()))
                 .subscribeOn(Schedulers.newThread())
                 .observeOn(AndroidSchedulers.mainThread())
                 .retry(1)
@@ -437,11 +437,11 @@ public class OperationsMenuController extends BaseController {
                                         .getFeatures() != null && capabilitiesOverall.getOcs().getData()
                                 .getCapabilities().getSpreedCapability()
                                 .getFeatures().contains("chat-v2")) {
-                            if (room.isHasPassword() && room.isGuest()) {
+                            if (conversation.isHasPassword() && conversation.isGuest()) {
                                 eventBus.post(new BottomSheetLockEvent(true, 0,
                                         true, false));
                                 Bundle bundle = new Bundle();
-                                bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room));
+                                bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
                                 bundle.putString(BundleKeys.KEY_CALL_URL, callUrl);
                                 bundle.putParcelable(BundleKeys.KEY_SPREED_CAPABILITIES,
                                         Parcels.wrap(capabilitiesOverall.getOcs().getData().getCapabilities()
@@ -486,7 +486,7 @@ public class OperationsMenuController extends BaseController {
         if (localInvitedUsers.size() > 0) {
             for (int i = 0; i < invitedUsers.size(); i++) {
                 final String userId = invitedUsers.get(i);
-                retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(currentUser.getBaseUrl(), room.getToken(),
+                retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(currentUser.getBaseUrl(), conversation.getToken(),
                         userId);
 
                 ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
@@ -547,9 +547,9 @@ public class OperationsMenuController extends BaseController {
                     true, true, dismissView));
 
             Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class);
-            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, room.getToken());
-            bundle.putString(BundleKeys.KEY_ROOM_ID, room.getRoomId());
-            bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, room.getDisplayName());
+            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation.getToken());
+            bundle.putString(BundleKeys.KEY_ROOM_ID, conversation.getRoomId());
+            bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, conversation.getDisplayName());
             bundle.putParcelable(BundleKeys.KEY_ACTIVE_CONVERSATION, Parcels.wrap(call));
 
             conversationIntent.putExtras(bundle);
@@ -577,7 +577,7 @@ public class OperationsMenuController extends BaseController {
     private void initiateCall() {
         eventBus.post(new BottomSheetLockEvent(true, 0, true, true));
         Bundle bundle = new Bundle();
-        bundle.putString(BundleKeys.KEY_ROOM_TOKEN, room.getToken());
+        bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation.getToken());
         bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(currentUser));
         if (baseUrl != null && !baseUrl.equals(currentUser.getBaseUrl())) {
             bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, baseUrl);

+ 4 - 4
app/src/main/java/com/nextcloud/talk/events/MoreMenuClickEvent.java

@@ -20,15 +20,15 @@
 
 package com.nextcloud.talk.events;
 
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 
 import lombok.Data;
 
 @Data
 public class MoreMenuClickEvent {
-    private final Room room;
+    private final Conversation conversation;
 
-    public MoreMenuClickEvent(Room room) {
-        this.room = room;
+    public MoreMenuClickEvent(Conversation conversation) {
+        this.conversation = conversation;
     }
 }

+ 4 - 4
app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java

@@ -51,7 +51,7 @@ import com.nextcloud.talk.models.RingtoneSettings;
 import com.nextcloud.talk.models.SignatureVerification;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.push.DecryptedPushMessage;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.models.json.rooms.RoomOverall;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DoNotDisturbUtils;
@@ -221,10 +221,10 @@ public class NotificationJob extends Job {
 
                     @Override
                     public void onNext(RoomOverall roomOverall) {
-                        Room room = roomOverall.getOcs().getData();
+                        Conversation conversation = roomOverall.getOcs().getData();
 
-                        intent.putExtra(BundleKeys.KEY_ROOM, Parcels.wrap(room));
-                        if (room.getType().equals(Room.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
+                        intent.putExtra(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
+                        if (conversation.getType().equals(Conversation.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
                             context.startActivity(intent);
                         } else {
                             showNotification(intent);

+ 8 - 8
app/src/main/java/com/nextcloud/talk/models/json/converters/EnumRoomTypeConverter.java

@@ -21,25 +21,25 @@
 package com.nextcloud.talk.models.json.converters;
 
 import com.bluelinelabs.logansquare.typeconverters.IntBasedTypeConverter;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 
-public class EnumRoomTypeConverter extends IntBasedTypeConverter<Room.RoomType> {
+public class EnumRoomTypeConverter extends IntBasedTypeConverter<Conversation.RoomType> {
     @Override
-    public Room.RoomType getFromInt(int i) {
+    public Conversation.RoomType getFromInt(int i) {
         switch (i) {
             case 1:
-                return Room.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL;
+                return Conversation.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL;
             case 2:
-                return Room.RoomType.ROOM_GROUP_CALL;
+                return Conversation.RoomType.ROOM_GROUP_CALL;
             case 3:
-                return Room.RoomType.ROOM_PUBLIC_CALL;
+                return Conversation.RoomType.ROOM_PUBLIC_CALL;
             default:
-                return Room.RoomType.DUMMY;
+                return Conversation.RoomType.DUMMY;
         }
     }
 
     @Override
-    public int convertToInt(Room.RoomType object) {
+    public int convertToInt(Conversation.RoomType object) {
         switch (object) {
             case DUMMY:
                 return 0;

+ 2 - 2
app/src/main/java/com/nextcloud/talk/models/json/participants/AddParticipantOCS.java

@@ -23,7 +23,7 @@ package com.nextcloud.talk.models.json.participants;
 import com.bluelinelabs.logansquare.annotation.JsonField;
 import com.bluelinelabs.logansquare.annotation.JsonObject;
 import com.nextcloud.talk.models.json.generic.GenericOCS;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 
 @JsonObject
 public class AddParticipantOCS extends GenericOCS {
@@ -31,5 +31,5 @@ public class AddParticipantOCS extends GenericOCS {
         Returned room will have only type set, and sometimes even that will be null
      */
     @JsonField(name = "data")
-    Room data;
+    Conversation data;
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java → app/src/main/java/com/nextcloud/talk/models/json/rooms/Conversation.java

@@ -36,7 +36,7 @@ import lombok.Data;
 @Parcel
 @Data
 @JsonObject
-public class Room {
+public class Conversation {
     @JsonField(name = "id")
     public String roomId;
     @JsonField(name = "token")

+ 1 - 1
app/src/main/java/com/nextcloud/talk/models/json/rooms/RoomOCS.java

@@ -30,5 +30,5 @@ import lombok.Data;
 @JsonObject
 public class RoomOCS extends GenericOCS {
     @JsonField(name = "data")
-    Room data;
+    Conversation data;
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/models/json/rooms/RoomsOCS.java

@@ -35,5 +35,5 @@ import lombok.Data;
 @JsonObject
 public class RoomsOCS extends GenericOCS {
     @JsonField(name = "data")
-    List<Room> data;
+    List<Conversation> data;
 }

+ 4 - 4
app/src/main/java/com/nextcloud/talk/utils/ShareUtils.java

@@ -34,7 +34,7 @@ import android.text.TextUtils;
 import com.kennyc.bottomsheet.adapters.AppAdapter;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.models.database.UserEntity;
-import com.nextcloud.talk.models.json.rooms.Room;
+import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 
 import java.util.ArrayList;
@@ -43,14 +43,14 @@ import java.util.Set;
 
 public class ShareUtils {
 
-    public static String getStringForIntent(Context context, @Nullable String password, UserUtils userUtils, Room
-            room) {
+    public static String getStringForIntent(Context context, @Nullable String password, UserUtils userUtils, Conversation
+            conversation) {
         UserEntity userEntity = userUtils.getCurrentUser();
 
         String shareString = "";
         if (userEntity != null && context != null) {
             shareString = String.format(context.getResources().getString(R.string.nc_share_text),
-                    userEntity.getBaseUrl(), room.getToken());
+                    userEntity.getBaseUrl(), conversation.getToken());
 
             if (!TextUtils.isEmpty(password)) {
                 shareString += String.format(context.getResources().getString(R.string.nc_share_text_pass), password);

+ 31 - 0
app/src/main/res/drawable/bubble_circle_unread.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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/>.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <solid android:color="@color/nc_darkRed" />
+    <stroke
+        android:width="2dp"
+        android:color="@color/white" />
+    <size
+        android:width="20dp"
+        android:height="20dp" />
+</shape>

+ 31 - 0
app/src/main/res/drawable/bubble_circle_unread_mention.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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/>.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <solid android:color="@color/colorPrimary" />
+    <stroke
+        android:width="2dp"
+        android:color="@color/white" />
+    <size
+        android:width="20dp"
+        android:height="20dp" />
+</shape>

+ 13 - 0
app/src/main/res/drawable/shape_bubble_offline.xml

@@ -0,0 +1,13 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+
+    <solid android:color="#AAAAAA"/>
+
+    <stroke
+        android:width="2dp"
+        android:color="@color/white"/>
+
+    <size
+        android:width="20dp"
+        android:height="20dp"/>
+</shape>

+ 13 - 0
app/src/main/res/drawable/shape_bubble_online.xml

@@ -0,0 +1,13 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+
+    <solid android:color="#38C059"/>
+
+    <stroke
+        android:width="2dp"
+        android:color="@color/white"/>
+
+    <size
+        android:width="20dp"
+        android:height="20dp"/>
+</shape>

+ 119 - 0
app/src/main/res/layout/rv_item_conversation_with_last_message.xml

@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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/>.
+  ~
+  ~
+  ~
+  ~ Adapted from https://github.com/stfalcon-studio/ChatKit/blob/master/chatkit/src/main/res/layout/item_dialog.xml
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="16dp"
+                android:layout_margin="16dp">
+
+
+    <FrameLayout
+        android:layout_width="@dimen/avatar_size"
+        android:layout_height="@dimen/avatar_size"
+        android:layout_centerVertical="true"
+        android:id="@+id/dialogAvatarFrameLayout">
+
+        <ImageView
+            android:id="@id/dialogAvatar"
+            android:layout_width="@dimen/avatar_size"
+            android:layout_height="@dimen/avatar_size"/>
+
+        <ImageView
+            android:id="@+id/onlineIndicator"
+            android:layout_width="12dp"
+            android:layout_height="12dp"
+            android:layout_gravity="top|end"
+            android:background="@drawable/shape_bubble_online"
+            />
+
+    </FrameLayout>
+
+    <TextView
+        android:id="@id/dialogName"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@id/dialogAvatarFrameLayout"
+        android:layout_marginStart="8dp"
+        android:layout_toEndOf="@id/dialogAvatarFrameLayout"
+        android:layout_toStartOf="@id/dialogDate"
+        android:ellipsize="end"
+        android:fontFamily="@string/font_fontFamily_medium"
+        android:includeFontPadding="false"
+        android:maxLines="1"/>
+
+    <TextView
+        android:id="@id/dialogDate"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:ellipsize="end"
+        android:maxLines="1"/>
+
+    <RelativeLayout
+        android:id="@+id/dialogLastMessageLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/dialogName"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_toEndOf="@id/dialogAvatarFrameLayout">
+
+        <ImageView
+            android:id="@id/dialogLastMessageUserAvatar"
+            android:layout_width="@dimen/small_item_height"
+            android:layout_height="@dimen/small_item_height"
+            android:layout_marginEnd="8dp"
+            android:layout_centerVertical="true"/>
+
+        <TextView
+            android:id="@id/dialogLastMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/dialogLastMessageUserAvatar"
+            android:layout_toStartOf="@id/dialogUnreadBubble"
+            android:ellipsize="end"
+            android:gravity="top"
+            android:maxLines="2"/>
+
+        <TextView
+            android:id="@id/dialogUnreadBubble"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            android:layout_alignParentEnd="true"
+            android:layout_marginStart="8dp"
+            android:background="@drawable/bubble_circle_unread"
+            android:ellipsize="end"
+            android:gravity="center"
+            android:textAlignment="center"
+            android:lines="1"
+            android:textColor="@color/white"/>
+
+
+    </RelativeLayout>
+
+</RelativeLayout>

+ 1 - 1
app/src/main/res/values-cs-rCZ/strings.xml

@@ -63,7 +63,7 @@
 
     <string name="nc_select_an_account">Vyberte účet</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Začněte konverzaci</string>
     <string name="nc_configure_room">Nastavení konverzace</string>
     <string name="nc_leave">Opustit konverzaci</string>

+ 1 - 1
app/src/main/res/values-de-rDE/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Konto auswählen</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Starte eine Unterhaltung</string>
     <string name="nc_configure_room">Unterhaltung einrichten</string>
     <string name="nc_leave">Unterhaltung verlassen</string>

+ 1 - 1
app/src/main/res/values-de/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Konto auswählen</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Starte eine Unterhaltung</string>
     <string name="nc_configure_room">Unterhaltung einrichten</string>
     <string name="nc_leave">Unterhaltung verlassen</string>

+ 1 - 1
app/src/main/res/values-es/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Selecciona una cuenta</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Comienza una conversación</string>
     <string name="nc_configure_room">Configura la conversación</string>
     <string name="nc_leave">Abandonar conversación</string>

+ 1 - 1
app/src/main/res/values-fr/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Choisissez un compte</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Commencer une conversation</string>
     <string name="nc_configure_room">Configurer la conversation</string>
     <string name="nc_leave">Quitter la conversation</string>

+ 1 - 1
app/src/main/res/values-hu-rHU/strings.xml

@@ -67,7 +67,7 @@
 
     <string name="nc_select_an_account">Fiók kiválasztása</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Beszélgetés indítása</string>
     <string name="nc_configure_room">Beszélgetés beállításai</string>
     <string name="nc_leave">Kilépés a beszélgetésből</string>

+ 1 - 1
app/src/main/res/values-is/strings.xml

@@ -66,7 +66,7 @@
 
     <string name="nc_select_an_account">Veldu aðgang</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Hefja samtal</string>
     <string name="nc_configure_room">Stilla samtal</string>
     <string name="nc_leave">Hætta í samtali</string>

+ 1 - 1
app/src/main/res/values-it/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Seleziona account</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Inizia una conversazione</string>
     <string name="nc_configure_room">Configura conversazione</string>
     <string name="nc_leave">Lascia la conversazione</string>

+ 1 - 1
app/src/main/res/values-iw/strings.xml

@@ -68,7 +68,7 @@
 
     <string name="nc_select_an_account">בחירת חשבון</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">התחלת דיון</string>
     <string name="nc_configure_room">הגדרת דיון</string>
     <string name="nc_leave">יציאה מהדיון</string>

+ 1 - 1
app/src/main/res/values-pt-rBR/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Selecionar uma conta</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Iniciar uma conversa</string>
     <string name="nc_configure_room">Configurar uma conversa</string>
     <string name="nc_leave">Sair da conversa</string>

+ 1 - 1
app/src/main/res/values-ru/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Выберите учётную запись</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Начать беседу</string>
     <string name="nc_configure_room">Настроить беседу</string>
     <string name="nc_leave">Покинуть беседу</string>

+ 1 - 1
app/src/main/res/values-sk-rSK/strings.xml

@@ -70,7 +70,7 @@
 
     <string name="nc_select_an_account">Zvoľte si účet</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Začať rozhovor</string>
     <string name="nc_configure_room">Nastavenia rozhovoru</string>
     <string name="nc_leave">Odísť z rozhovoru</string>

+ 1 - 1
app/src/main/res/values-sr/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Изаберите налог</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Започни разговор</string>
     <string name="nc_configure_room">Подеси разговор</string>
     <string name="nc_leave">Напусти разговор</string>

+ 1 - 1
app/src/main/res/values-tr/strings.xml

@@ -72,7 +72,7 @@
 
     <string name="nc_select_an_account">Bir hesap seçin</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Yeni bir görüşme başlat</string>
     <string name="nc_configure_room">Görüşmeyi yapılandır</string>
     <string name="nc_leave">Görüşmeden ayrıl</string>

+ 1 - 1
app/src/main/res/values-vi/strings.xml

@@ -70,7 +70,7 @@
 
     <string name="nc_select_an_account">Chọn một tài khoản</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Bắt đầu một cuộc Đàm thoại</string>
     <string name="nc_configure_room">Cấu hình đàm thoại</string>
     <string name="nc_leave">Rời khỏi cuộc đàm thoại</string>

+ 1 - 1
app/src/main/res/values-zh-rCN/strings.xml

@@ -67,7 +67,7 @@
 
     <string name="nc_select_an_account">选择一个账户</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">发起会话</string>
     <string name="nc_configure_room">配置会话</string>
     <string name="nc_leave">离开会话</string>

+ 3 - 1
app/src/main/res/values/strings.xml

@@ -86,7 +86,7 @@
 
     <string name="nc_select_an_account">Select an account</string>
 
-    <!-- Room menu -->
+    <!-- Conversation menu -->
     <string name="nc_start_conversation">Start a conversation</string>
     <string name="nc_configure_room">Configure conversation</string>
     <string name="nc_leave">Leave conversation</string>
@@ -186,6 +186,8 @@ Find Nextcloud on https://nextcloud.com</string>
     <string name="nc_conversation_menu_voice_call">Voice call</string>
     <string name="nc_conversation_menu_video_call">Video call</string>
     <string name="nc_new_messages">New messages</string>
+    <string name="nc_no_messages_yet">No messages yet</string>
+    <string name="nc_chat_you">You</string>
 
     <!-- Contacts endless loading -->
     <string name="nc_no_more_load_retry">No more items to load. Refresh to retry.</string>