Browse Source

Merge pull request #1832 from nextcloud/feature/1829/itemViewBinding

Migrate view items to native view bindings
Marcel Hibbe 3 years ago
parent
commit
d378c35df1

+ 1 - 2
app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java

@@ -4,7 +4,7 @@
  * @author Mario Danic
  * @author Mario Danic
  * @author Andy Scherzinger
  * @author Andy Scherzinger
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
- * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -78,7 +78,6 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
     /**
     /**
      * @return the model object
      * @return the model object
      */
      */
-
     public Participant getModel() {
     public Participant getModel() {
         return participant;
         return participant;
     }
     }

+ 0 - 125
app/src/main/java/com/nextcloud/talk/adapters/items/AppItem.java

@@ -1,125 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017 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.graphics.drawable.Drawable;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-import androidx.annotation.Nullable;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import eu.davidea.flexibleadapter.FlexibleAdapter;
-import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
-import eu.davidea.flexibleadapter.items.IFlexible;
-import eu.davidea.viewholders.FlexibleViewHolder;
-
-import java.util.List;
-
-public class AppItem extends AbstractFlexibleItem<AppItem.AppItemViewHolder> {
-    private String title;
-    private String packageName;
-    private String name;
-    @Nullable
-    private Drawable drawable;
-
-    public AppItem(String title, String packageName, String name, @Nullable Drawable drawable) {
-        this.title = title;
-        this.packageName = packageName;
-        this.name = name;
-        this.drawable = drawable;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof AppItem) {
-            AppItem inItem = (AppItem) o;
-            return title.equals(inItem.getTitle()) && packageName.equals(inItem.getPackageName()) && name.equals(inItem
-                    .getName());
-        }
-
-        return false;
-    }
-
-    public String getTitle() {
-        return title;
-    }
-
-    public String getPackageName() {
-        return packageName;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public int getLayoutRes() {
-        return R.layout.rv_item_app;
-    }
-
-    @Override
-    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, AppItemViewHolder holder, int position, List<Object> payloads) {
-        if (drawable != null) {
-            holder.iconImageView.setVisibility(View.VISIBLE);
-            holder.iconImageView.setImageDrawable(drawable);
-        } else {
-            holder.iconImageView.setVisibility(View.GONE);
-        }
-
-        if (position == 0) {
-            Spannable spannableString = new SpannableString(title);
-            spannableString.setSpan(new ForegroundColorSpan(NextcloudTalkApplication.Companion.getSharedApplication()
-                            .getResources().getColor(R.color.grey_600)), 0,
-                    spannableString.length(),
-                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            holder.appTitleTextView.setText(spannableString);
-        } else {
-            holder.appTitleTextView.setText(title);
-        }
-    }
-
-    @Override
-    public AppItem.AppItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
-        return new AppItemViewHolder(view, adapter);
-    }
-
-    static class AppItemViewHolder extends FlexibleViewHolder {
-        @BindView(R.id.icon_image_view)
-        public ImageView iconImageView;
-        @BindView(R.id.app_title_text_view)
-        public TextView appTitleTextView;
-
-        /**
-         * Default constructor.
-         */
-        AppItemViewHolder(View view, FlexibleAdapter adapter) {
-            super(view, adapter);
-            ButterKnife.bind(this, view);
-        }
-    }
-
-}

+ 237 - 0
app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.java

@@ -0,0 +1,237 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * @author Marcel Hibbe
+ * @author Andy Scherzinger
+ * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
+ * Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
+ * Copyright (C) 2017 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.annotation.SuppressLint;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.nextcloud.talk.R;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.databinding.RvItemContactBinding;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.models.json.participants.Participant;
+import com.nextcloud.talk.utils.ApiUtils;
+import com.nextcloud.talk.utils.DisplayUtils;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import androidx.core.content.res.ResourcesCompat;
+import eu.davidea.flexibleadapter.FlexibleAdapter;
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
+import eu.davidea.flexibleadapter.items.IFilterable;
+import eu.davidea.flexibleadapter.items.ISectionable;
+import eu.davidea.flexibleadapter.utils.FlexibleUtils;
+import eu.davidea.viewholders.FlexibleViewHolder;
+
+public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemViewHolder> implements
+    ISectionable<ContactItem.ContactItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
+
+    public static final String PARTICIPANT_SOURCE_CIRCLES = "circles";
+    public static final String PARTICIPANT_SOURCE_GROUPS = "groups";
+    public static final String PARTICIPANT_SOURCE_USERS = "users";
+
+    private final Participant participant;
+    private final UserEntity userEntity;
+    private GenericTextHeaderItem header;
+    public boolean isOnline = true;
+
+    public ContactItem(Participant participant,
+                       UserEntity userEntity,
+                       GenericTextHeaderItem genericTextHeaderItem) {
+        this.participant = participant;
+        this.userEntity = userEntity;
+        this.header = genericTextHeaderItem;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof ContactItem) {
+            ContactItem inItem = (ContactItem) o;
+            return participant.getActorType() == inItem.getModel().getActorType() &&
+                participant.getActorId().equals(inItem.getModel().getActorId());
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return participant.hashCode();
+    }
+
+    /**
+     * @return the model object
+     */
+    public Participant getModel() {
+        return participant;
+    }
+
+
+    @Override
+    public int getLayoutRes() {
+        return R.layout.rv_item_contact;
+    }
+
+    @Override
+    public ContactItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
+        return new ContactItemViewHolder(view, adapter);
+    }
+
+    @SuppressLint("SetTextI18n")
+    @Override
+    public void bindViewHolder(FlexibleAdapter adapter, ContactItemViewHolder holder, int position, List payloads) {
+        holder.binding.avatarDraweeView.setController(null);
+
+        if (participant.isSelected()) {
+            holder.binding.checkedImageView.setVisibility(View.VISIBLE);
+        } else {
+            holder.binding.checkedImageView.setVisibility(View.GONE);
+        }
+
+        if (!isOnline) {
+            holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
+                holder.binding.nameText.getContext().getResources(),
+                R.color.medium_emphasis_text,
+                null)
+                                                );
+            holder.binding.avatarDraweeView.setAlpha(0.38f);
+        } else {
+            holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
+                holder.binding.nameText.getContext().getResources(),
+                R.color.high_emphasis_text,
+                null)
+                                                );
+            holder.binding.avatarDraweeView.setAlpha(1.0f);
+        }
+
+        if (adapter.hasFilter()) {
+            FlexibleUtils.highlightText(holder.binding.nameText,
+                                        participant.getDisplayName(),
+                                        String.valueOf(adapter.getFilter(String.class)),
+                                        NextcloudTalkApplication
+                                            .Companion
+                                            .getSharedApplication()
+                                            .getResources()
+                                            .getColor(R.color.colorPrimary));
+        }
+
+        holder.binding.nameText.setText(participant.getDisplayName());
+
+        if (TextUtils.isEmpty(participant.getDisplayName()) &&
+            (participant.getType().equals(Participant.ParticipantType.GUEST) ||
+                participant.getType().equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
+            holder.binding.nameText.setText(NextcloudTalkApplication
+                                                .Companion
+                                                .getSharedApplication()
+                                                .getString(R.string.nc_guest));
+        }
+
+        if (
+            participant.getActorType() == Participant.ActorType.GROUPS ||
+                PARTICIPANT_SOURCE_GROUPS.equals(participant.getSource()) ||
+                participant.getActorType() == Participant.ActorType.CIRCLES ||
+                PARTICIPANT_SOURCE_CIRCLES.equals(participant.getSource())) {
+
+            holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_group);
+
+        } else if (participant.getActorType() == Participant.ActorType.EMAILS) {
+
+            holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_mail);
+
+        } else if (
+            participant.getActorType() == Participant.ActorType.GUESTS ||
+                Participant.ParticipantType.GUEST.equals(participant.getType()) ||
+                Participant.ParticipantType.GUEST_MODERATOR.equals(participant.getType())) {
+
+            String displayName = NextcloudTalkApplication.Companion.getSharedApplication()
+                .getResources().getString(R.string.nc_guest);
+
+            if (!TextUtils.isEmpty(participant.getDisplayName())) {
+                displayName = participant.getDisplayName();
+            }
+
+            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                .setOldController(holder.binding.avatarDraweeView.getController())
+                .setAutoPlayAnimations(true)
+                .setImageRequest(DisplayUtils.getImageRequestForUrl(
+                    ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(),
+                                                              displayName,
+                                                              R.dimen.avatar_size),
+                    null))
+                .build();
+            holder.binding.avatarDraweeView.setController(draweeController);
+
+        } else if (participant.getActorType() == Participant.ActorType.USERS ||
+            PARTICIPANT_SOURCE_USERS.equals(participant.getSource())) {
+            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                .setOldController(holder.binding.avatarDraweeView.getController())
+                .setAutoPlayAnimations(true)
+                .setImageRequest(DisplayUtils.getImageRequestForUrl(
+                    ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                                                     participant.getActorId(),
+                                                     R.dimen.avatar_size),
+                    null))
+                .build();
+            holder.binding.avatarDraweeView.setController(draweeController);
+        }
+    }
+
+    @Override
+    public boolean filter(String constraint) {
+        return participant.getDisplayName() != null &&
+            (Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+                .matcher(participant.getDisplayName().trim())
+                .find() ||
+                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+                    .matcher(participant.getActorId().trim())
+                    .find());
+    }
+
+    @Override
+    public GenericTextHeaderItem getHeader() {
+        return header;
+    }
+
+    @Override
+    public void setHeader(GenericTextHeaderItem header) {
+        this.header = header;
+    }
+
+    static class ContactItemViewHolder extends FlexibleViewHolder {
+
+        RvItemContactBinding binding;
+
+        /**
+         * Default constructor.
+         */
+        ContactItemViewHolder(View view, FlexibleAdapter adapter) {
+            super(view, adapter);
+            binding = RvItemContactBinding.bind(view);
+        }
+    }
+}

+ 94 - 87
app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java

@@ -36,20 +36,17 @@ import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.format.DateUtils;
 import android.view.View;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.ImageView;
-import android.widget.TextView;
 
 
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.drawee.interfaces.DraweeController;
 import com.facebook.drawee.interfaces.DraweeController;
-import com.facebook.drawee.view.SimpleDraweeView;
-import com.google.android.material.chip.Chip;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.databinding.RvItemConversationWithLastMessageBinding;
 import com.nextcloud.talk.models.database.CapabilitiesUtil;
 import com.nextcloud.talk.models.database.CapabilitiesUtil;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.models.json.conversations.Conversation;
 import com.nextcloud.talk.models.json.conversations.Conversation;
 import com.nextcloud.talk.models.json.status.Status;
 import com.nextcloud.talk.models.json.status.Status;
-import com.nextcloud.talk.models.json.status.StatusType;
 import com.nextcloud.talk.ui.StatusDrawable;
 import com.nextcloud.talk.ui.StatusDrawable;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
@@ -59,9 +56,6 @@ import java.util.regex.Pattern;
 
 
 import androidx.core.content.ContextCompat;
 import androidx.core.content.ContextCompat;
 import androidx.core.content.res.ResourcesCompat;
 import androidx.core.content.res.ResourcesCompat;
-import androidx.emoji.widget.EmojiTextView;
-import butterknife.BindView;
-import butterknife.ButterKnife;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.IFilterable;
@@ -70,16 +64,16 @@ import eu.davidea.flexibleadapter.items.ISectionable;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.viewholders.FlexibleViewHolder;
 import eu.davidea.viewholders.FlexibleViewHolder;
 
 
-public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements ISectionable<ConversationItem.ConversationItemViewHolder, GenericTextHeaderItem>,
-    IFilterable<String> {
+public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements
+    ISectionable<ConversationItem.ConversationItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
 
 
     private static final float STATUS_SIZE_IN_DP = 9f;
     private static final float STATUS_SIZE_IN_DP = 9f;
 
 
-    private Conversation conversation;
-    private UserEntity userEntity;
-    private Context context;
+    private final Conversation conversation;
+    private final UserEntity userEntity;
+    private final Context context;
     private GenericTextHeaderItem header;
     private GenericTextHeaderItem header;
-    private Status status;
+    private final Status status;
 
 
     public ConversationItem(Conversation conversation, UserEntity userEntity, Context activityContext, Status status) {
     public ConversationItem(Conversation conversation, UserEntity userEntity, Context activityContext, Status status) {
         this.conversation = conversation;
         this.conversation = conversation;
@@ -127,31 +121,38 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
 
 
     @SuppressLint("SetTextI18n")
     @SuppressLint("SetTextI18n")
     @Override
     @Override
-    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ConversationItemViewHolder holder, int position, List<Object> payloads) {
+    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter,
+                               ConversationItemViewHolder holder,
+                               int position,
+                               List<Object> payloads) {
         Context appContext =
         Context appContext =
             NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext();
             NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext();
-        holder.dialogAvatar.setController(null);
+        holder.binding.dialogAvatar.setController(null);
 
 
-        holder.dialogName.setTextColor(ResourcesCompat.getColor(context.getResources(),
-                                                                R.color.conversation_item_header,
-                                                                null));
+        holder.binding.dialogName.setTextColor(ResourcesCompat.getColor(context.getResources(),
+                                                                        R.color.conversation_item_header,
+                                                                        null));
 
 
         if (adapter.hasFilter()) {
         if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(holder.dialogName, conversation.getDisplayName(),
-                                        String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication()
-                                            .getResources().getColor(R.color.colorPrimary));
+            FlexibleUtils.highlightText(holder.binding.dialogName, conversation.getDisplayName(),
+                                        String.valueOf(adapter.getFilter(String.class)),
+                                        NextcloudTalkApplication
+                                            .Companion
+                                            .getSharedApplication()
+                                            .getResources()
+                                            .getColor(R.color.colorPrimary));
         } else {
         } else {
-            holder.dialogName.setText(conversation.getDisplayName());
+            holder.binding.dialogName.setText(conversation.getDisplayName());
         }
         }
 
 
         if (conversation.getUnreadMessages() > 0) {
         if (conversation.getUnreadMessages() > 0) {
-            holder.dialogName.setTypeface(holder.dialogName.getTypeface(), Typeface.BOLD);
-            holder.dialogLastMessage.setTypeface(holder.dialogLastMessage.getTypeface(), Typeface.BOLD);
-            holder.dialogUnreadBubble.setVisibility(View.VISIBLE);
+            holder.binding.dialogName.setTypeface(holder.binding.dialogName.getTypeface(), Typeface.BOLD);
+            holder.binding.dialogLastMessage.setTypeface(holder.binding.dialogLastMessage.getTypeface(), Typeface.BOLD);
+            holder.binding.dialogUnreadBubble.setVisibility(View.VISIBLE);
             if (conversation.getUnreadMessages() < 1000) {
             if (conversation.getUnreadMessages() < 1000) {
-                holder.dialogUnreadBubble.setText(Long.toString(conversation.getUnreadMessages()));
+                holder.binding.dialogUnreadBubble.setText(Long.toString(conversation.getUnreadMessages()));
             } else {
             } else {
-                holder.dialogUnreadBubble.setText(R.string.tooManyUnreadMessages);
+                holder.binding.dialogUnreadBubble.setText(R.string.tooManyUnreadMessages);
             }
             }
 
 
             ColorStateList lightBubbleFillColor = ColorStateList.valueOf(
             ColorStateList lightBubbleFillColor = ColorStateList.valueOf(
@@ -165,45 +166,45 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                                        R.color.colorPrimary));
                                        R.color.colorPrimary));
 
 
             if (conversation.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
             if (conversation.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
-                holder.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
-                holder.dialogUnreadBubble.setTextColor(Color.WHITE);
+                holder.binding.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
+                holder.binding.dialogUnreadBubble.setTextColor(Color.WHITE);
             } else if (conversation.isUnreadMention()) {
             } else if (conversation.isUnreadMention()) {
                 if (CapabilitiesUtil.hasSpreedFeatureCapability(userEntity, "direct-mention-flag")) {
                 if (CapabilitiesUtil.hasSpreedFeatureCapability(userEntity, "direct-mention-flag")) {
                     if (conversation.getUnreadMentionDirect()) {
                     if (conversation.getUnreadMentionDirect()) {
-                        holder.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
-                        holder.dialogUnreadBubble.setTextColor(Color.WHITE);
+                        holder.binding.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
+                        holder.binding.dialogUnreadBubble.setTextColor(Color.WHITE);
                     } else {
                     } else {
-                        holder.dialogUnreadBubble.setChipBackgroundColorResource(R.color.bg_default);
-                        holder.dialogUnreadBubble.setTextColor(ContextCompat.getColor(
+                        holder.binding.dialogUnreadBubble.setChipBackgroundColorResource(R.color.bg_default);
+                        holder.binding.dialogUnreadBubble.setTextColor(ContextCompat.getColor(
                             context,
                             context,
                             R.color.colorPrimary));
                             R.color.colorPrimary));
-                        holder.dialogUnreadBubble.setChipStrokeWidth(6.0f);
-                        holder.dialogUnreadBubble.setChipStrokeColor(lightBubbleStrokeColor);
+                        holder.binding.dialogUnreadBubble.setChipStrokeWidth(6.0f);
+                        holder.binding.dialogUnreadBubble.setChipStrokeColor(lightBubbleStrokeColor);
                     }
                     }
                 } else {
                 } else {
-                    holder.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
-                    holder.dialogUnreadBubble.setTextColor(Color.WHITE);
+                    holder.binding.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
+                    holder.binding.dialogUnreadBubble.setTextColor(Color.WHITE);
                 }
                 }
             } else {
             } else {
-                holder.dialogUnreadBubble.setChipBackgroundColor(lightBubbleFillColor);
-                holder.dialogUnreadBubble.setTextColor(lightBubbleTextColor);
+                holder.binding.dialogUnreadBubble.setChipBackgroundColor(lightBubbleFillColor);
+                holder.binding.dialogUnreadBubble.setTextColor(lightBubbleTextColor);
             }
             }
         } else {
         } else {
-            holder.dialogName.setTypeface(null, Typeface.NORMAL);
-            holder.dialogDate.setTypeface(null, Typeface.NORMAL);
-            holder.dialogLastMessage.setTypeface(null, Typeface.NORMAL);
-            holder.dialogUnreadBubble.setVisibility(View.GONE);
+            holder.binding.dialogName.setTypeface(null, Typeface.NORMAL);
+            holder.binding.dialogDate.setTypeface(null, Typeface.NORMAL);
+            holder.binding.dialogLastMessage.setTypeface(null, Typeface.NORMAL);
+            holder.binding.dialogUnreadBubble.setVisibility(View.GONE);
         }
         }
 
 
         if (conversation.isFavorite()) {
         if (conversation.isFavorite()) {
-            holder.pinnedConversationImageView.setVisibility(View.VISIBLE);
+            holder.binding.favoriteConversationImageView.setVisibility(View.VISIBLE);
         } else {
         } else {
-            holder.pinnedConversationImageView.setVisibility(View.GONE);
+            holder.binding.favoriteConversationImageView.setVisibility(View.GONE);
         }
         }
 
 
         if (Conversation.ConversationType.ROOM_SYSTEM != conversation.getType()) {
         if (Conversation.ConversationType.ROOM_SYSTEM != conversation.getType()) {
             float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, appContext);
             float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, appContext);
-            holder.userStatusImage.setImageDrawable(new StatusDrawable(
+            holder.binding.userStatusImage.setImageDrawable(new StatusDrawable(
                 status != null ? status.getStatus() : "",
                 status != null ? status.getStatus() : "",
                 status != null ? status.getIcon() : "",
                 status != null ? status.getIcon() : "",
                 size,
                 size,
@@ -212,12 +213,16 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
         }
         }
 
 
         if (conversation.getLastMessage() != null) {
         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 (!TextUtils.isEmpty(conversation.getLastMessage().getSystemMessage()) || Conversation.ConversationType.ROOM_SYSTEM == conversation.getType()) {
-                holder.dialogLastMessage.setText(conversation.getLastMessage().getText());
+            holder.binding.dialogDate.setVisibility(View.VISIBLE);
+            holder.binding.dialogDate.setText(
+                DateUtils.getRelativeTimeSpanString(conversation.getLastActivity() * 1000L,
+                                                    System.currentTimeMillis(),
+                                                    0,
+                                                    DateUtils.FORMAT_ABBREV_RELATIVE));
+
+            if (!TextUtils.isEmpty(conversation.getLastMessage().getSystemMessage()) ||
+                Conversation.ConversationType.ROOM_SYSTEM == conversation.getType()) {
+                holder.binding.dialogLastMessage.setText(conversation.getLastMessage().getText());
             } else {
             } else {
                 String authorDisplayName = "";
                 String authorDisplayName = "";
                 conversation.getLastMessage().setActiveUser(userEntity);
                 conversation.getLastMessage().setActiveUser(userEntity);
@@ -229,7 +234,8 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                     } else {
                     } else {
                         authorDisplayName = !TextUtils.isEmpty(conversation.getLastMessage().getActorDisplayName()) ?
                         authorDisplayName = !TextUtils.isEmpty(conversation.getLastMessage().getActorDisplayName()) ?
                             conversation.getLastMessage().getActorDisplayName() :
                             conversation.getLastMessage().getActorDisplayName() :
-                            "guests".equals(conversation.getLastMessage().getActorType()) ? appContext.getString(R.string.nc_guest) : "";
+                            "guests".equals(conversation.getLastMessage().getActorType()) ?
+                                appContext.getString(R.string.nc_guest) : "";
                         text = String.format(appContext.getString(R.string.nc_formatted_message),
                         text = String.format(appContext.getString(R.string.nc_formatted_message),
                                              authorDisplayName,
                                              authorDisplayName,
                                              conversation.getLastMessage().getLastMessageDisplayText());
                                              conversation.getLastMessage().getLastMessageDisplayText());
@@ -238,14 +244,14 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                     text = conversation.getLastMessage().getLastMessageDisplayText();
                     text = conversation.getLastMessage().getLastMessageDisplayText();
                 }
                 }
 
 
-                holder.dialogLastMessage.setText(text);
+                holder.binding.dialogLastMessage.setText(text);
             }
             }
         } else {
         } else {
-            holder.dialogDate.setVisibility(View.GONE);
-            holder.dialogLastMessage.setText(R.string.nc_no_messages_yet);
+            holder.binding.dialogDate.setVisibility(View.GONE);
+            holder.binding.dialogLastMessage.setText(R.string.nc_no_messages_yet);
         }
         }
 
 
-        holder.dialogAvatar.setVisibility(View.VISIBLE);
+        holder.binding.dialogAvatar.setVisibility(View.VISIBLE);
 
 
         boolean shouldLoadAvatar = true;
         boolean shouldLoadAvatar = true;
         String objectType;
         String objectType;
@@ -253,13 +259,15 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
             switch (objectType) {
             switch (objectType) {
                 case "share:password":
                 case "share:password":
                     shouldLoadAvatar = false;
                     shouldLoadAvatar = false;
-                    holder.dialogAvatar.setImageDrawable(ContextCompat.getDrawable(context,
-                                                                                   R.drawable.ic_circular_lock));
+                    holder.binding.dialogAvatar.setImageDrawable(
+                        ContextCompat.getDrawable(context,
+                                                  R.drawable.ic_circular_lock));
                     break;
                     break;
                 case "file":
                 case "file":
                     shouldLoadAvatar = false;
                     shouldLoadAvatar = false;
-                    holder.dialogAvatar.setImageDrawable(ContextCompat.getDrawable(context,
-                                                                                   R.drawable.ic_circular_document));
+                    holder.binding.dialogAvatar.setImageDrawable(
+                        ContextCompat.getDrawable(context,
+                                                  R.drawable.ic_circular_document));
                     break;
                     break;
                 default:
                 default:
                     break;
                     break;
@@ -273,9 +281,10 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                 layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground);
                 layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground);
                 LayerDrawable layerDrawable = new LayerDrawable(layers);
                 LayerDrawable layerDrawable = new LayerDrawable(layers);
 
 
-                holder.dialogAvatar.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
+                holder.binding.dialogAvatar.getHierarchy().setPlaceholderImage(
+                    DisplayUtils.getRoundedDrawable(layerDrawable));
             } else {
             } else {
-                holder.dialogAvatar.getHierarchy().setPlaceholderImage(R.mipmap.ic_launcher);
+                holder.binding.dialogAvatar.getHierarchy().setPlaceholderImage(R.mipmap.ic_launcher);
             }
             }
             shouldLoadAvatar = false;
             shouldLoadAvatar = false;
         }
         }
@@ -285,25 +294,31 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                 case ROOM_TYPE_ONE_TO_ONE_CALL:
                 case ROOM_TYPE_ONE_TO_ONE_CALL:
                     if (!TextUtils.isEmpty(conversation.getName())) {
                     if (!TextUtils.isEmpty(conversation.getName())) {
                         DraweeController draweeController = Fresco.newDraweeControllerBuilder()
                         DraweeController draweeController = Fresco.newDraweeControllerBuilder()
-                            .setOldController(holder.dialogAvatar.getController())
+                            .setOldController(holder.binding.dialogAvatar.getController())
                             .setAutoPlayAnimations(true)
                             .setAutoPlayAnimations(true)
-                            .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getName(), R.dimen.avatar_size), userEntity))
+                            .setImageRequest(DisplayUtils.getImageRequestForUrl(
+                                ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                                                                 conversation.getName(),
+                                                                 R.dimen.avatar_size),
+                                userEntity))
                             .build();
                             .build();
-                        holder.dialogAvatar.setController(draweeController);
+                        holder.binding.dialogAvatar.setController(draweeController);
                     } else {
                     } else {
-                        holder.dialogAvatar.setVisibility(View.GONE);
+                        holder.binding.dialogAvatar.setVisibility(View.GONE);
                     }
                     }
                     break;
                     break;
                 case ROOM_GROUP_CALL:
                 case ROOM_GROUP_CALL:
-                    holder.dialogAvatar.setImageDrawable(ContextCompat.getDrawable(context,
-                                                                                   R.drawable.ic_circular_group));
+                    holder.binding.dialogAvatar.setImageDrawable(
+                        ContextCompat.getDrawable(context,
+                                                  R.drawable.ic_circular_group));
                     break;
                     break;
                 case ROOM_PUBLIC_CALL:
                 case ROOM_PUBLIC_CALL:
-                    holder.dialogAvatar.setImageDrawable(ContextCompat.getDrawable(context,
-                                                                                   R.drawable.ic_circular_link));
+                    holder.binding.dialogAvatar.setImageDrawable(
+                        ContextCompat.getDrawable(context,
+                                                  R.drawable.ic_circular_link));
                     break;
                     break;
                 default:
                 default:
-                    holder.dialogAvatar.setVisibility(View.GONE);
+                    holder.binding.dialogAvatar.setVisibility(View.GONE);
             }
             }
         }
         }
     }
     }
@@ -311,7 +326,10 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
     @Override
     @Override
     public boolean filter(String constraint) {
     public boolean filter(String constraint) {
         return conversation.getDisplayName() != null &&
         return conversation.getDisplayName() != null &&
-            Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
+            Pattern
+                .compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+                .matcher(conversation.getDisplayName().trim())
+                .find();
     }
     }
 
 
     @Override
     @Override
@@ -325,24 +343,13 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
     }
     }
 
 
     static class ConversationItemViewHolder extends FlexibleViewHolder {
     static class ConversationItemViewHolder extends FlexibleViewHolder {
-        @BindView(R.id.dialogAvatar)
-        SimpleDraweeView dialogAvatar;
-        @BindView(R.id.dialogName)
-        EmojiTextView dialogName;
-        @BindView(R.id.dialogDate)
-        TextView dialogDate;
-        @BindView(R.id.dialogLastMessage)
-        EmojiTextView dialogLastMessage;
-        @BindView(R.id.dialogUnreadBubble)
-        Chip dialogUnreadBubble;
-        @BindView(R.id.favoriteConversationImageView)
-        ImageView pinnedConversationImageView;
-        @BindView(R.id.user_status_image)
         ImageView userStatusImage;
         ImageView userStatusImage;
 
 
+        RvItemConversationWithLastMessageBinding binding;
+
         ConversationItemViewHolder(View view, FlexibleAdapter adapter) {
         ConversationItemViewHolder(View view, FlexibleAdapter adapter) {
             super(view, adapter);
             super(view, adapter);
-            ButterKnife.bind(this, view);
+            binding = RvItemConversationWithLastMessageBinding.bind(view);
         }
         }
     }
     }
 }
 }

+ 11 - 12
app/src/main/java/com/nextcloud/talk/adapters/items/GenericTextHeaderItem.java

@@ -2,6 +2,8 @@
  * Nextcloud Talk application
  * Nextcloud Talk application
  *
  *
  * @author Mario Danic
  * @author Mario Danic
+ * @author Andy Scherzinger
+ * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
  * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * This program is free software: you can redistribute it and/or modify
@@ -22,21 +24,21 @@ package com.nextcloud.talk.adapters.items;
 
 
 import android.util.Log;
 import android.util.Log;
 import android.view.View;
 import android.view.View;
-import android.widget.TextView;
-import butterknife.BindView;
-import butterknife.ButterKnife;
+
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.R;
+import com.nextcloud.talk.databinding.RvItemTitleHeaderBinding;
+
+import java.util.List;
+
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractHeaderItem;
 import eu.davidea.flexibleadapter.items.AbstractHeaderItem;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.viewholders.FlexibleViewHolder;
 import eu.davidea.viewholders.FlexibleViewHolder;
 
 
-import java.util.List;
-
 public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> {
 public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> {
     private static final String TAG = "GenericTextHeaderItem";
     private static final String TAG = "GenericTextHeaderItem";
 
 
-    private String title;
+    private final String title;
 
 
     public GenericTextHeaderItem(String title) {
     public GenericTextHeaderItem(String title) {
         super();
         super();
@@ -68,9 +70,8 @@ public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderI
         if (payloads.size() > 0) {
         if (payloads.size() > 0) {
             Log.d(TAG, "We have payloads, so ignoring!");
             Log.d(TAG, "We have payloads, so ignoring!");
         } else {
         } else {
-            holder.titleTextView.setText(title);
+            holder.binding.titleTextView.setText(title);
         }
         }
-
     }
     }
 
 
     @Override
     @Override
@@ -80,16 +81,14 @@ public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderI
 
 
     static class HeaderViewHolder extends FlexibleViewHolder {
     static class HeaderViewHolder extends FlexibleViewHolder {
 
 
-        @BindView(R.id.title_text_view)
-        public TextView titleTextView;
+        RvItemTitleHeaderBinding binding;
 
 
         /**
         /**
          * Default constructor.
          * Default constructor.
          */
          */
         HeaderViewHolder(View view, FlexibleAdapter adapter) {
         HeaderViewHolder(View view, FlexibleAdapter adapter) {
             super(view, adapter, true);
             super(view, adapter, true);
-            ButterKnife.bind(this, view);
+            binding = RvItemTitleHeaderBinding.bind(view);
         }
         }
     }
     }
-
 }
 }

+ 58 - 53
app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java

@@ -1,10 +1,12 @@
 /*
 /*
  * Nextcloud Talk application
  * Nextcloud Talk application
  *
  *
- * @author Marcel Hibbe
  * @author Mario Danic
  * @author Mario Danic
- * Copyright (C) 2022 Marcel Hibbe (dev@mhibbe.de)
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ * @author Marcel Hibbe
+ * @author Andy Scherzinger
+ * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
+ * Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -49,8 +51,8 @@ import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 
 
-public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
-        implements IFilterable<String> {
+public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantItem.ParticipantItemViewHolder>
+    implements IFilterable<String> {
 
 
     private static final float STATUS_SIZE_IN_DP = 9f;
     private static final float STATUS_SIZE_IN_DP = 9f;
     private static final String NO_ICON = "";
     private static final String NO_ICON = "";
@@ -67,9 +69,9 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
     private final Context context;
     private final Context context;
 
 
     public MentionAutocompleteItem(
     public MentionAutocompleteItem(
-            Mention mention,
-            UserEntity currentUser,
-            Context activityContext) {
+        Mention mention,
+        UserEntity currentUser,
+        Context activityContext) {
         this.objectId = mention.getId();
         this.objectId = mention.getId();
         this.displayName = mention.getLabel();
         this.displayName = mention.getLabel();
         this.source = mention.getSource();
         this.source = mention.getSource();
@@ -112,45 +114,46 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
     }
     }
 
 
     @Override
     @Override
-    public UserItem.UserItemViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
-        return new UserItem.UserItemViewHolder(view, adapter);
+    public ParticipantItem.ParticipantItemViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
+        return new ParticipantItem.ParticipantItemViewHolder(view, adapter);
     }
     }
 
 
-
     @SuppressLint("SetTextI18n")
     @SuppressLint("SetTextI18n")
     @Override
     @Override
-    public void bindViewHolder(
-            FlexibleAdapter<IFlexible> adapter,
-            UserItem.UserItemViewHolder holder,
-            int position,
-            List<Object> payloads) {
-
-        holder.contactDisplayName.setTextColor(ResourcesCompat.getColor(context.getResources(),
-                                                                        R.color.conversation_item_header,
-                                                                        null));
+    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter,
+                               ParticipantItem.ParticipantItemViewHolder holder,
+                               int position,
+                               List<Object> payloads) {
+
+        holder.binding.nameText.setTextColor(
+            ResourcesCompat.getColor(context.getResources(),
+                                     R.color.conversation_item_header,
+                                     null));
         if (adapter.hasFilter()) {
         if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(holder.contactDisplayName,
+            FlexibleUtils.highlightText(holder.binding.nameText,
                                         displayName,
                                         displayName,
                                         String.valueOf(adapter.getFilter(String.class)),
                                         String.valueOf(adapter.getFilter(String.class)),
-                                        Objects.requireNonNull(NextcloudTalkApplication.Companion.getSharedApplication())
+                                        Objects.requireNonNull(NextcloudTalkApplication
+                                                                   .Companion
+                                                                   .getSharedApplication())
                                             .getResources().getColor(R.color.colorPrimary));
                                             .getResources().getColor(R.color.colorPrimary));
-            if (holder.contactMentionId != null) {
-                FlexibleUtils.highlightText(holder.contactMentionId,
+            if (holder.binding.secondaryText != null) {
+                FlexibleUtils.highlightText(holder.binding.secondaryText,
                                             "@" + objectId,
                                             "@" + objectId,
                                             String.valueOf(adapter.getFilter(String.class)),
                                             String.valueOf(adapter.getFilter(String.class)),
                                             NextcloudTalkApplication.Companion.getSharedApplication()
                                             NextcloudTalkApplication.Companion.getSharedApplication()
                                                 .getResources().getColor(R.color.colorPrimary));
                                                 .getResources().getColor(R.color.colorPrimary));
             }
             }
         } else {
         } else {
-            holder.contactDisplayName.setText(displayName);
-            if (holder.contactMentionId != null) {
-                holder.contactMentionId.setText("@" + objectId);
+            holder.binding.nameText.setText(displayName);
+            if (holder.binding.secondaryText != null) {
+                holder.binding.secondaryText.setText("@" + objectId);
             }
             }
         }
         }
 
 
         if (SOURCE_CALLS.equals(source)) {
         if (SOURCE_CALLS.equals(source)) {
-            if (holder.participantAvatar != null){
-                holder.participantAvatar.setImageResource(R.drawable.ic_circular_group);
+            if (holder.binding.avatarDraweeView != null) {
+                holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_group);
             }
             }
         } else {
         } else {
             String avatarId = objectId;
             String avatarId = objectId;
@@ -165,25 +168,27 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
                     R.dimen.avatar_size_big);
                     R.dimen.avatar_size_big);
             }
             }
 
 
-            if(holder.participantAvatar != null){
-                holder.participantAvatar.setController(null);
+            if (holder.binding.avatarDraweeView != null) {
+                holder.binding.avatarDraweeView.setController(null);
             }
             }
 
 
             DraweeController draweeController = Fresco.newDraweeControllerBuilder()
             DraweeController draweeController = Fresco.newDraweeControllerBuilder()
-                .setOldController(holder.participantAvatar.getController())
+                .setOldController(holder.binding.avatarDraweeView.getController())
                 .setAutoPlayAnimations(true)
                 .setAutoPlayAnimations(true)
                 .setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl, null))
                 .setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl, null))
                 .build();
                 .build();
-            holder.participantAvatar.setController(draweeController);
+            holder.binding.avatarDraweeView.setController(draweeController);
         }
         }
 
 
         drawStatus(holder);
         drawStatus(holder);
     }
     }
 
 
-    private void drawStatus(UserItem.UserItemViewHolder holder) {
-        if (holder.statusMessage != null && holder.participantEmoji != null && holder.userStatusImage != null) {
+    private void drawStatus(ParticipantItem.ParticipantItemViewHolder holder) {
+        if (holder.binding.conversationInfoStatusMessage != null &&
+            holder.binding.participantStatusEmoji != null &&
+            holder.binding.userStatusImage != null) {
             float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, context);
             float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, context);
-            holder.userStatusImage.setImageDrawable(new StatusDrawable(
+            holder.binding.userStatusImage.setImageDrawable(new StatusDrawable(
                 status,
                 status,
                 NO_ICON,
                 NO_ICON,
                 size,
                 size,
@@ -191,49 +196,49 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
                 context));
                 context));
 
 
             if (statusMessage != null) {
             if (statusMessage != null) {
-                holder.statusMessage.setText(statusMessage);
+                holder.binding.conversationInfoStatusMessage.setText(statusMessage);
                 alignUsernameVertical(holder, 0);
                 alignUsernameVertical(holder, 0);
             } else {
             } else {
-                holder.statusMessage.setText("");
+                holder.binding.conversationInfoStatusMessage.setText("");
                 alignUsernameVertical(holder, 10);
                 alignUsernameVertical(holder, 10);
             }
             }
 
 
             if (statusIcon != null && !statusIcon.isEmpty()) {
             if (statusIcon != null && !statusIcon.isEmpty()) {
-                holder.participantEmoji.setText(statusIcon);
+                holder.binding.participantStatusEmoji.setText(statusIcon);
             } else {
             } else {
-                holder.participantEmoji.setVisibility(View.GONE);
+                holder.binding.participantStatusEmoji.setVisibility(View.GONE);
             }
             }
 
 
             if (status != null && status.equals(StatusType.DND.getString())) {
             if (status != null && status.equals(StatusType.DND.getString())) {
                 if (statusMessage == null || statusMessage.isEmpty()) {
                 if (statusMessage == null || statusMessage.isEmpty()) {
-                    holder.statusMessage.setText(R.string.dnd);
+                    holder.binding.conversationInfoStatusMessage.setText(R.string.dnd);
                 }
                 }
             } else if (status != null && status.equals(StatusType.AWAY.getString())) {
             } else if (status != null && status.equals(StatusType.AWAY.getString())) {
                 if (statusMessage == null || statusMessage.isEmpty()) {
                 if (statusMessage == null || statusMessage.isEmpty()) {
-                    holder.statusMessage.setText(R.string.away);
+                    holder.binding.conversationInfoStatusMessage.setText(R.string.away);
                 }
                 }
             }
             }
         }
         }
     }
     }
 
 
-    private void alignUsernameVertical(UserItem.UserItemViewHolder holder, float densityPixelsFromTop) {
+    private void alignUsernameVertical(ParticipantItem.ParticipantItemViewHolder holder, float densityPixelsFromTop) {
         ConstraintLayout.LayoutParams layoutParams =
         ConstraintLayout.LayoutParams layoutParams =
-            (ConstraintLayout.LayoutParams) holder.contactDisplayName.getLayoutParams();
+            (ConstraintLayout.LayoutParams) holder.binding.nameText.getLayoutParams();
         layoutParams.topMargin = (int) DisplayUtils.convertDpToPixel(densityPixelsFromTop, context);
         layoutParams.topMargin = (int) DisplayUtils.convertDpToPixel(densityPixelsFromTop, context);
-        holder.contactDisplayName.setLayoutParams(layoutParams);
+        holder.binding.nameText.setLayoutParams(layoutParams);
     }
     }
 
 
     @Override
     @Override
     public boolean filter(String constraint) {
     public boolean filter(String constraint) {
         return objectId != null &&
         return objectId != null &&
+            Pattern
+                .compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+                .matcher(objectId)
+                .find() ||
+            displayName != null &&
                 Pattern
                 Pattern
-                        .compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
-                        .matcher(objectId)
-                        .find() ||
-                displayName != null &&
-                        Pattern
-                                .compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
-                                .matcher(displayName)
-                                .find();
+                    .compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+                    .matcher(displayName)
+                    .find();
     }
     }
 }
 }

+ 0 - 109
app/src/main/java/com/nextcloud/talk/adapters/items/MenuItem.java

@@ -1,109 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * @author Andy Scherzinger
- * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
- * Copyright (C) 2018 Andy Scherzinger
- *
- * 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.graphics.drawable.Drawable;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
-import android.view.View;
-import android.widget.TextView;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.utils.DisplayUtils;
-import eu.davidea.flexibleadapter.FlexibleAdapter;
-import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
-import eu.davidea.viewholders.FlexibleViewHolder;
-
-import java.util.List;
-
-public class MenuItem extends AbstractFlexibleItem<MenuItem.MenuItemViewHolder> {
-    private String title;
-    private Drawable icon;
-    private int tag;
-    private int padding;
-
-    public MenuItem(String title, int tag, Drawable icon) {
-        this.title = title;
-        this.tag = tag;
-        this.icon = icon;
-        padding = (int) DisplayUtils.convertDpToPixel(32,
-                NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext());
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof MenuItem) {
-            MenuItem inItem = (MenuItem) o;
-            return tag == inItem.tag;
-        }
-        return false;
-    }
-
-    public int getTag() {
-        return tag;
-    }
-
-    @Override
-    public int getLayoutRes() {
-        return R.layout.rv_item_menu;
-    }
-
-    @Override
-    public MenuItem.MenuItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
-        return new MenuItemViewHolder(view, adapter);
-    }
-
-    @Override
-    public void bindViewHolder(FlexibleAdapter adapter, MenuItem.MenuItemViewHolder holder, int position, List payloads) {
-        if (position == 0) {
-            Spannable spannableString = new SpannableString(title);
-            spannableString.setSpan(new ForegroundColorSpan(NextcloudTalkApplication.Companion.getSharedApplication()
-                            .getResources().getColor(R.color.grey_600)), 0,
-                    spannableString.length(),
-                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            holder.menuTitle.setText(spannableString);
-        } else {
-            holder.menuTitle.setText(title);
-            holder.menuTitle.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
-            holder.menuTitle.setCompoundDrawablePadding(padding);
-        }
-    }
-
-    static class MenuItemViewHolder extends FlexibleViewHolder {
-
-        @BindView(R.id.menu_text)
-        public TextView menuTitle;
-
-        /**
-         * Default constructor.
-         */
-        MenuItemViewHolder(View view, FlexibleAdapter adapter) {
-            super(view, adapter);
-            ButterKnife.bind(this, view);
-        }
-    }
-}

+ 12 - 9
app/src/main/java/com/nextcloud/talk/adapters/items/NotificationSoundItem.java

@@ -2,6 +2,8 @@
  * Nextcloud Talk application
  * Nextcloud Talk application
  *
  *
  * @author Mario Danic
  * @author Mario Danic
+ * @author Andy Scherzinger
+ * Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
  * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
  * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * This program is free software: you can redistribute it and/or modify
@@ -22,13 +24,11 @@ package com.nextcloud.talk.adapters.items;
 
 
 import android.view.View;
 import android.view.View;
 
 
-import com.google.android.material.radiobutton.MaterialRadioButton;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.R;
+import com.nextcloud.talk.databinding.RvItemNotificationSoundBinding;
 
 
 import java.util.List;
 import java.util.List;
 
 
-import butterknife.BindView;
-import butterknife.ButterKnife;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.flexibleadapter.items.IFlexible;
@@ -68,21 +68,24 @@ public class NotificationSoundItem extends AbstractFlexibleItem<NotificationSoun
     }
     }
 
 
     @Override
     @Override
-    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, NotificationSoundItemViewHolder holder, int position, List<Object> payloads) {
-        holder.notificationName.setText(notificationSoundName);
-        holder.notificationName.setChecked(adapter.isSelected(position));
+    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter,
+                               NotificationSoundItemViewHolder holder,
+                               int position,
+                               List<Object> payloads) {
+        holder.binding.notificationNameTextView.setText(notificationSoundName);
+        holder.binding.notificationNameTextView.setChecked(adapter.isSelected(position));
     }
     }
 
 
     static class NotificationSoundItemViewHolder extends FlexibleViewHolder {
     static class NotificationSoundItemViewHolder extends FlexibleViewHolder {
-        @BindView(R.id.notificationNameTextView)
-        public MaterialRadioButton notificationName;
+
+        RvItemNotificationSoundBinding binding;
 
 
         /**
         /**
          * Default constructor.
          * Default constructor.
          */
          */
         NotificationSoundItemViewHolder(View view, FlexibleAdapter adapter) {
         NotificationSoundItemViewHolder(View view, FlexibleAdapter adapter) {
             super(view, adapter);
             super(view, adapter);
-            ButterKnife.bind(this, view);
+            binding = RvItemNotificationSoundBinding.bind(view);
         }
         }
     }
     }
 }
 }

+ 332 - 0
app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.java

@@ -0,0 +1,332 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * @author Marcel Hibbe
+ * @author Andy Scherzinger
+ * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
+ * Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
+ * Copyright (C) 2017 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.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.nextcloud.talk.R;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.databinding.RvItemConversationInfoParticipantBinding;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter;
+import com.nextcloud.talk.models.json.participants.Participant;
+import com.nextcloud.talk.models.json.participants.Participant.InCallFlags;
+import com.nextcloud.talk.models.json.status.StatusType;
+import com.nextcloud.talk.ui.StatusDrawable;
+import com.nextcloud.talk.utils.ApiUtils;
+import com.nextcloud.talk.utils.DisplayUtils;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.content.res.ResourcesCompat;
+import eu.davidea.flexibleadapter.FlexibleAdapter;
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
+import eu.davidea.flexibleadapter.items.IFilterable;
+import eu.davidea.flexibleadapter.utils.FlexibleUtils;
+import eu.davidea.viewholders.FlexibleViewHolder;
+
+public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.ParticipantItemViewHolder> implements
+    IFilterable<String> {
+
+    private static final float STATUS_SIZE_IN_DP = 9f;
+    private static final String NO_ICON = "";
+
+    private final Context context;
+    private final Participant participant;
+    private final UserEntity userEntity;
+    public boolean isOnline = true;
+
+    public ParticipantItem(Context activityContext,
+                           Participant participant,
+                           UserEntity userEntity) {
+        this.context = activityContext;
+        this.participant = participant;
+        this.userEntity = userEntity;
+    }
+
+    public Participant getModel() {
+        return participant;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof ParticipantItem) {
+            ParticipantItem inItem = (ParticipantItem) o;
+            return participant.getActorType() == inItem.getModel().getActorType() &&
+                participant.getActorId().equals(inItem.getModel().getActorId());
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return participant.hashCode();
+    }
+
+    @Override
+    public int getLayoutRes() {
+        return R.layout.rv_item_conversation_info_participant;
+    }
+
+    @Override
+    public ParticipantItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
+        return new ParticipantItemViewHolder(view, adapter);
+    }
+
+    @SuppressLint("SetTextI18n")
+    @Override
+    public void bindViewHolder(FlexibleAdapter adapter, ParticipantItemViewHolder holder, int position, List payloads) {
+
+        holder.binding.avatarDraweeView.setController(null);
+
+        drawStatus(holder);
+
+        if (!isOnline) {
+            holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
+                holder.binding.nameText.getContext().getResources(),
+                R.color.medium_emphasis_text,
+                null)
+                                                );
+            holder.binding.avatarDraweeView.setAlpha(0.38f);
+        } else {
+            holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
+                holder.binding.nameText.getContext().getResources(),
+                R.color.high_emphasis_text,
+                null)
+                                                );
+            holder.binding.avatarDraweeView.setAlpha(1.0f);
+        }
+
+        if (adapter.hasFilter()) {
+            FlexibleUtils.highlightText(holder.binding.nameText, participant.getDisplayName(),
+                                        String.valueOf(adapter.getFilter(String.class)),
+                                        NextcloudTalkApplication.Companion.getSharedApplication()
+                                            .getResources()
+                                            .getColor(R.color.colorPrimary));
+        }
+
+        holder.binding.nameText.setText(participant.getDisplayName());
+
+        if (TextUtils.isEmpty(participant.getDisplayName()) &&
+            (participant.getType().equals(Participant.ParticipantType.GUEST) ||
+                participant.getType().equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
+            holder.binding.nameText.setText(NextcloudTalkApplication
+                                                .Companion
+                                                .getSharedApplication()
+                                                .getString(R.string.nc_guest));
+        }
+
+        if (participant.getActorType() == Participant.ActorType.GROUPS ||
+            "groups".equals(participant.getSource()) ||
+            participant.getActorType() == Participant.ActorType.CIRCLES ||
+            "circles".equals(participant.getSource())) {
+            holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_group);
+        } else if (participant.getActorType() == Participant.ActorType.EMAILS) {
+            holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_mail);
+        } else if (participant.getActorType() == Participant.ActorType.GUESTS ||
+            Participant.ParticipantType.GUEST.equals(participant.getType()) ||
+            Participant.ParticipantType.GUEST_MODERATOR.equals(participant.getType())) {
+
+            String displayName = NextcloudTalkApplication.Companion.getSharedApplication()
+                .getResources().getString(R.string.nc_guest);
+
+            if (!TextUtils.isEmpty(participant.getDisplayName())) {
+                displayName = participant.getDisplayName();
+            }
+
+            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                .setOldController(holder.binding.avatarDraweeView.getController())
+                .setAutoPlayAnimations(true)
+                .setImageRequest(DisplayUtils.getImageRequestForUrl(
+                    ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(),
+                                                              displayName, R.dimen.avatar_size), null))
+                .build();
+            holder.binding.avatarDraweeView.setController(draweeController);
+
+        } else if (participant.getActorType() == Participant.ActorType.USERS ||
+            participant.getSource().equals("users")) {
+            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                .setOldController(holder.binding.avatarDraweeView.getController())
+                .setAutoPlayAnimations(true)
+                .setImageRequest(DisplayUtils.getImageRequestForUrl(
+                    ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                                                     participant.getActorId(), R.dimen.avatar_size), null))
+                .build();
+            holder.binding.avatarDraweeView.setController(draweeController);
+        }
+
+        Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
+
+        Long inCallFlag = participant.getInCall();
+        if ((inCallFlag & InCallFlags.WITH_PHONE) > 0) {
+            holder.binding.videoCallIcon.setImageResource(R.drawable.ic_call_grey_600_24dp);
+            holder.binding.videoCallIcon.setVisibility(View.VISIBLE);
+            holder.binding.videoCallIcon.setContentDescription(
+                resources.getString(R.string.nc_call_state_with_phone, participant.displayName));
+        } else if ((inCallFlag & InCallFlags.WITH_VIDEO) > 0) {
+            holder.binding.videoCallIcon.setImageResource(R.drawable.ic_videocam_grey_600_24dp);
+            holder.binding.videoCallIcon.setVisibility(View.VISIBLE);
+            holder.binding.videoCallIcon.setContentDescription(
+                resources.getString(R.string.nc_call_state_with_video, participant.displayName));
+        } else if (inCallFlag > InCallFlags.DISCONNECTED) {
+            holder.binding.videoCallIcon.setImageResource(R.drawable.ic_mic_grey_600_24dp);
+            holder.binding.videoCallIcon.setVisibility(View.VISIBLE);
+            holder.binding.videoCallIcon.setContentDescription(
+                resources.getString(R.string.nc_call_state_in_call, participant.displayName));
+        } else {
+            holder.binding.videoCallIcon.setVisibility(View.GONE);
+        }
+
+        if (holder.binding.secondaryText != null) {
+            String userType = "";
+
+            switch (new EnumParticipantTypeConverter().convertToInt(participant.getType())) {
+                case 1:
+                    //userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_owner);
+                    //break;
+                case 2:
+                case 6: // Guest moderator
+                    userType = NextcloudTalkApplication
+                        .Companion
+                        .getSharedApplication()
+                        .getString(R.string.nc_moderator);
+                    break;
+                case 3:
+                    userType = NextcloudTalkApplication
+                        .Companion
+                        .getSharedApplication()
+                        .getString(R.string.nc_user);
+                    if (participant.getActorType() == Participant.ActorType.GROUPS) {
+                        userType = NextcloudTalkApplication
+                            .Companion
+                            .getSharedApplication()
+                            .getString(R.string.nc_group);
+                    }
+                    if (participant.getActorType() == Participant.ActorType.CIRCLES) {
+                        userType = NextcloudTalkApplication
+                            .Companion
+                            .getSharedApplication()
+                            .getString(R.string.nc_circle);
+                    }
+                    break;
+                case 4:
+                    userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest);
+                    if (participant.getActorType() == Participant.ActorType.EMAILS) {
+                        userType = NextcloudTalkApplication
+                            .Companion
+                            .getSharedApplication()
+                            .getString(R.string.nc_email);
+                    }
+                    break;
+                case 5:
+                    userType = NextcloudTalkApplication
+                        .Companion
+                        .getSharedApplication()
+                        .getString(R.string.nc_following_link);
+                    break;
+                default:
+                    break;
+            }
+
+            if (!userType.equals(NextcloudTalkApplication
+                                     .Companion
+                                     .getSharedApplication()
+                                     .getString(R.string.nc_user))) {
+                holder.binding.secondaryText.setText("(" + userType + ")");
+            }
+        }
+    }
+
+    private void drawStatus(ParticipantItemViewHolder holder) {
+        float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, context);
+        holder.binding.userStatusImage.setImageDrawable(new StatusDrawable(
+            participant.status,
+            NO_ICON,
+            size,
+            context.getResources().getColor(R.color.bg_default),
+            context));
+
+        if (participant.statusMessage != null) {
+            holder.binding.conversationInfoStatusMessage.setText(participant.statusMessage);
+            alignUsernameVertical(holder, 0);
+        } else {
+            holder.binding.conversationInfoStatusMessage.setText("");
+            alignUsernameVertical(holder, 10);
+        }
+
+        if (participant.statusIcon != null && !participant.statusIcon.isEmpty()) {
+            holder.binding.participantStatusEmoji.setText(participant.statusIcon);
+        } else {
+            holder.binding.participantStatusEmoji.setVisibility(View.GONE);
+        }
+
+        if (participant.status != null && participant.status.equals(StatusType.DND.getString())) {
+            if (participant.statusMessage == null || participant.statusMessage.isEmpty()) {
+                holder.binding.conversationInfoStatusMessage.setText(R.string.dnd);
+            }
+        } else if (participant.status != null && participant.status.equals(StatusType.AWAY.getString())) {
+            if (participant.statusMessage == null || participant.statusMessage.isEmpty()) {
+                holder.binding.conversationInfoStatusMessage.setText(R.string.away);
+            }
+        }
+    }
+
+    private void alignUsernameVertical(ParticipantItem.ParticipantItemViewHolder holder, float densityPixelsFromTop) {
+        ConstraintLayout.LayoutParams layoutParams =
+            (ConstraintLayout.LayoutParams) holder.binding.nameText.getLayoutParams();
+        layoutParams.topMargin = (int) DisplayUtils.convertDpToPixel(densityPixelsFromTop, context);
+        holder.binding.nameText.setLayoutParams(layoutParams);
+    }
+
+    @Override
+    public boolean filter(String constraint) {
+        return participant.getDisplayName() != null &&
+            (Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+                .matcher(participant.getDisplayName().trim()).find() ||
+                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
+                    .matcher(participant.getActorId().trim()).find());
+    }
+
+    static class ParticipantItemViewHolder extends FlexibleViewHolder {
+
+        RvItemConversationInfoParticipantBinding binding;
+
+        /**
+         * Default constructor.
+         */
+        ParticipantItemViewHolder(View view, FlexibleAdapter adapter) {
+            super(view, adapter);
+            binding = RvItemConversationInfoParticipantBinding.bind(view);
+        }
+    }
+}

+ 0 - 142
app/src/main/java/com/nextcloud/talk/adapters/items/ProgressItem.java

@@ -1,142 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Heavily copied from and influenced by
- * https://github.com/davideas/FlexibleAdapter/wiki/5.x-%7C-On-Load-More#automatic-load-more.
- * Author: David Steduto under Apache2 licence
- */
-
-package com.nextcloud.talk.adapters.items;
-
-import android.animation.Animator;
-import android.content.Context;
-import android.view.View;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import androidx.annotation.NonNull;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.nextcloud.talk.R;
-import eu.davidea.flexibleadapter.FlexibleAdapter;
-import eu.davidea.flexibleadapter.Payload;
-import eu.davidea.flexibleadapter.helpers.AnimatorHelper;
-import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
-import eu.davidea.flexibleadapter.items.IFlexible;
-import eu.davidea.viewholders.FlexibleViewHolder;
-
-import java.util.List;
-
-/**
- * @author Davide Steduto
- * @since 22/04/2016
- */
-public class ProgressItem extends AbstractFlexibleItem<ProgressItem.ProgressViewHolder> {
-
-    private StatusEnum status = StatusEnum.MORE_TO_LOAD;
-
-    @Override
-    public boolean equals(Object o) {
-        return this == o;//The default implementation
-    }
-
-    public StatusEnum getStatus() {
-        return status;
-    }
-
-    public void setStatus(StatusEnum status) {
-        this.status = status;
-    }
-
-    @Override
-    public int getLayoutRes() {
-        return R.layout.rv_item_progress;
-    }
-
-    @Override
-    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ProgressViewHolder holder, int position, List<Object> payloads) {
-        Context context = holder.itemView.getContext();
-        holder.progressBar.setVisibility(View.GONE);
-        holder.progressMessage.setVisibility(View.VISIBLE);
-
-        if (!adapter.isEndlessScrollEnabled()) {
-            setStatus(StatusEnum.DISABLE_ENDLESS);
-        } else if (payloads.contains(Payload.NO_MORE_LOAD)) {
-            setStatus(StatusEnum.NO_MORE_LOAD);
-        }
-
-        switch (this.status) {
-            case NO_MORE_LOAD:
-                holder.progressMessage.setText(
-                        context.getString(R.string.nc_no_more_load_retry));
-                // Reset to default status for next binding
-                setStatus(StatusEnum.MORE_TO_LOAD);
-                break;
-            case DISABLE_ENDLESS:
-                holder.progressMessage.setText(context.getString(R.string.nc_endless_disabled));
-                break;
-            case ON_CANCEL:
-                holder.progressMessage.setText(context.getString(R.string.nc_endless_cancel));
-                // Reset to default status for next binding
-                setStatus(StatusEnum.MORE_TO_LOAD);
-                break;
-            case ON_ERROR:
-                holder.progressMessage.setText(context.getString(R.string.nc_endless_error));
-                // Reset to default status for next binding
-                setStatus(StatusEnum.MORE_TO_LOAD);
-                break;
-            default:
-                holder.progressBar.setVisibility(View.VISIBLE);
-                holder.progressMessage.setVisibility(View.GONE);
-                break;
-        }
-    }
-
-    @Override
-    public ProgressViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
-        return new ProgressViewHolder(view, adapter);
-    }
-
-
-    public enum StatusEnum {
-        MORE_TO_LOAD, //Default = should have an empty Payload
-        DISABLE_ENDLESS, //Endless is disabled because user has set limits
-        NO_MORE_LOAD, //Non-empty Payload = Payload.NO_MORE_LOAD
-        ON_CANCEL,
-        ON_ERROR
-    }
-
-    static class ProgressViewHolder extends FlexibleViewHolder {
-
-        @BindView(R.id.progress_bar)
-        ProgressBar progressBar;
-        @BindView(R.id.progress_message)
-        TextView progressMessage;
-
-        ProgressViewHolder(View view, FlexibleAdapter adapter) {
-            super(view, adapter);
-            ButterKnife.bind(this, view);
-        }
-
-        @Override
-        public void scrollAnimators(@NonNull List<Animator> animators, int position, boolean isForward) {
-            AnimatorHelper.scaleAnimator(animators, itemView, 0f);
-        }
-    }
-
-}

+ 0 - 366
app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java

@@ -1,366 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * @author Marcel Hibbe
- * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
- * Copyright (C) 2022 Marcel Hibbe (dev@mhibbe.de)
- *
- * 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.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.TextUtils;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.facebook.drawee.backends.pipeline.Fresco;
-import com.facebook.drawee.interfaces.DraweeController;
-import com.facebook.drawee.view.SimpleDraweeView;
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.models.database.UserEntity;
-import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter;
-import com.nextcloud.talk.models.json.participants.Participant;
-import com.nextcloud.talk.models.json.participants.Participant.InCallFlags;
-import com.nextcloud.talk.models.json.status.StatusType;
-import com.nextcloud.talk.ui.StatusDrawable;
-import com.nextcloud.talk.utils.ApiUtils;
-import com.nextcloud.talk.utils.DisplayUtils;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-import androidx.annotation.Nullable;
-import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.core.content.res.ResourcesCompat;
-import androidx.emoji.widget.EmojiTextView;
-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.ISectionable;
-import eu.davidea.flexibleadapter.utils.FlexibleUtils;
-import eu.davidea.viewholders.FlexibleViewHolder;
-
-public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> implements
-    ISectionable<UserItem.UserItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
-
-    private static final float STATUS_SIZE_IN_DP = 9f;
-    private static final String NO_ICON = "";
-
-    private Context context;
-    private Participant participant;
-    private UserEntity userEntity;
-    private GenericTextHeaderItem header;
-    public boolean isOnline = true;
-
-    public UserItem(Context activityContext,
-                    Participant participant,
-                    UserEntity userEntity,
-                    GenericTextHeaderItem genericTextHeaderItem) {
-        this.context = activityContext;
-        this.participant = participant;
-        this.userEntity = userEntity;
-        this.header = genericTextHeaderItem;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof UserItem) {
-            UserItem inItem = (UserItem) o;
-            return participant.getActorType() == inItem.getModel().getActorType() &&
-                participant.getActorId().equals(inItem.getModel().getActorId());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return participant.hashCode();
-    }
-
-    /**
-     * @return the model object
-     */
-
-    public Participant getModel() {
-        return participant;
-    }
-
-    public UserEntity getEntity() {
-        return userEntity;
-    }
-
-
-    @Override
-    public int getLayoutRes() {
-        if (header != null) {
-            return R.layout.rv_item_contact;
-        } else {
-            return R.layout.rv_item_conversation_info_participant;
-        }
-    }
-
-    @Override
-    public UserItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
-        return new UserItemViewHolder(view, adapter);
-    }
-
-    @SuppressLint("SetTextI18n")
-    @Override
-    public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
-
-        if (holder.participantAvatar != null) {
-            holder.participantAvatar.setController(null);
-        }
-
-        if (holder.checkedImageView != null) {
-            if (participant.isSelected()) {
-                holder.checkedImageView.setVisibility(View.VISIBLE);
-            } else {
-                holder.checkedImageView.setVisibility(View.GONE);
-            }
-        }
-
-        drawStatus(holder);
-
-        if (!isOnline) {
-            holder.contactDisplayName.setTextColor(ResourcesCompat.getColor(
-                holder.contactDisplayName.getContext().getResources(),
-                R.color.medium_emphasis_text,
-                null)
-                                                  );
-            holder.participantAvatar.setAlpha(0.38f);
-        } else {
-            holder.contactDisplayName.setTextColor(ResourcesCompat.getColor(
-                holder.contactDisplayName.getContext().getResources(),
-                R.color.high_emphasis_text,
-                null)
-                                                  );
-            holder.participantAvatar.setAlpha(1.0f);
-        }
-
-        if (adapter.hasFilter()) {
-            FlexibleUtils.highlightText(holder.contactDisplayName, participant.getDisplayName(),
-                                        String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication()
-                                            .getResources().getColor(R.color.colorPrimary));
-        }
-
-        holder.contactDisplayName.setText(participant.getDisplayName());
-
-        if (TextUtils.isEmpty(participant.getDisplayName()) &&
-            (participant.getType().equals(Participant.ParticipantType.GUEST) || participant.getType().equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
-            holder.contactDisplayName.setText(NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest));
-        }
-
-        if (participant.getActorType() == Participant.ActorType.GROUPS ||
-            "groups".equals(participant.getSource()) ||
-            participant.getActorType() == Participant.ActorType.CIRCLES ||
-            "circles".equals(participant.getSource())) {
-            holder.participantAvatar.setImageResource(R.drawable.ic_circular_group);
-        } else if (participant.getActorType() == Participant.ActorType.EMAILS) {
-            holder.participantAvatar.setImageResource(R.drawable.ic_circular_mail);
-        } else if (participant.getActorType() == Participant.ActorType.GUESTS ||
-            Participant.ParticipantType.GUEST.equals(participant.getType()) ||
-            Participant.ParticipantType.GUEST_MODERATOR.equals(participant.getType())) {
-
-            String displayName = NextcloudTalkApplication.Companion.getSharedApplication()
-                .getResources().getString(R.string.nc_guest);
-
-            if (!TextUtils.isEmpty(participant.getDisplayName())) {
-                displayName = participant.getDisplayName();
-            }
-
-            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
-                .setOldController(holder.participantAvatar.getController())
-                .setAutoPlayAnimations(true)
-                .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(),
-                                                                                                              displayName, R.dimen.avatar_size), null))
-                .build();
-            holder.participantAvatar.setController(draweeController);
-
-        } else if (participant.getActorType() == Participant.ActorType.USERS || participant.getSource().equals("users")) {
-            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
-                .setOldController(holder.participantAvatar.getController())
-                .setAutoPlayAnimations(true)
-                .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
-                                                                                                     participant.getActorId(), R.dimen.avatar_size), null))
-                .build();
-            holder.participantAvatar.setController(draweeController);
-        }
-
-        Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
-
-        if (header == null) {
-            Long inCallFlag = participant.getInCall();
-            if ((inCallFlag & InCallFlags.WITH_PHONE) > 0) {
-                holder.videoCallIconView.setImageResource(R.drawable.ic_call_grey_600_24dp);
-                holder.videoCallIconView.setVisibility(View.VISIBLE);
-                holder.videoCallIconView.setContentDescription(
-                    resources.getString(R.string.nc_call_state_with_phone, participant.displayName));
-            } else if ((inCallFlag & InCallFlags.WITH_VIDEO) > 0) {
-                holder.videoCallIconView.setImageResource(R.drawable.ic_videocam_grey_600_24dp);
-                holder.videoCallIconView.setVisibility(View.VISIBLE);
-                holder.videoCallIconView.setContentDescription(
-                    resources.getString(R.string.nc_call_state_with_video, participant.displayName));
-            } else if (inCallFlag > InCallFlags.DISCONNECTED) {
-                holder.videoCallIconView.setImageResource(R.drawable.ic_mic_grey_600_24dp);
-                holder.videoCallIconView.setVisibility(View.VISIBLE);
-                holder.videoCallIconView.setContentDescription(
-                    resources.getString(R.string.nc_call_state_in_call, participant.displayName));
-            } else {
-                holder.videoCallIconView.setVisibility(View.GONE);
-            }
-
-            if (holder.contactMentionId != null) {
-                String userType = "";
-
-                switch (new EnumParticipantTypeConverter().convertToInt(participant.getType())) {
-                    case 1:
-                        //userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_owner);
-                        //break;
-                    case 2:
-                    case 6: // Guest moderator
-                        userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_moderator);
-                        break;
-                    case 3:
-                        userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_user);
-                        if (participant.getActorType() == Participant.ActorType.GROUPS) {
-                            userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_group);
-                        }
-                        if (participant.getActorType() == Participant.ActorType.CIRCLES) {
-                            userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_circle);
-                        }
-                        break;
-                    case 4:
-                        userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest);
-                        if (participant.getActorType() == Participant.ActorType.EMAILS) {
-                            userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_email);
-                        }
-                        break;
-                    case 5:
-                        userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_following_link);
-                        break;
-                    default:
-                        break;
-                }
-
-                if (!userType.equals(NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_user))) {
-                    holder.contactMentionId.setText("(" + userType + ")");
-                }
-            }
-        }
-    }
-
-    private void drawStatus(UserItemViewHolder holder) {
-        if (holder.statusMessage != null && holder.participantEmoji != null && holder.userStatusImage != null) {
-            float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, context);
-            holder.userStatusImage.setImageDrawable(new StatusDrawable(
-                participant.status,
-                NO_ICON,
-                size,
-                context.getResources().getColor(R.color.bg_default),
-                context));
-
-            if (participant.statusMessage != null) {
-                holder.statusMessage.setText(participant.statusMessage);
-                alignUsernameVertical(holder, 0);
-            } else {
-                holder.statusMessage.setText("");
-                alignUsernameVertical(holder, 10);
-            }
-
-            if (participant.statusIcon != null && !participant.statusIcon.isEmpty()) {
-                holder.participantEmoji.setText(participant.statusIcon);
-            } else {
-                holder.participantEmoji.setVisibility(View.GONE);
-            }
-
-            if (participant.status != null && participant.status.equals(StatusType.DND.getString())) {
-                if (participant.statusMessage == null || participant.statusMessage.isEmpty()) {
-                    holder.statusMessage.setText(R.string.dnd);
-                }
-            } else if (participant.status != null && participant.status.equals(StatusType.AWAY.getString())) {
-                if (participant.statusMessage == null || participant.statusMessage.isEmpty()) {
-                    holder.statusMessage.setText(R.string.away);
-                }
-            }
-        }
-    }
-
-    private void alignUsernameVertical(UserItem.UserItemViewHolder holder, float densityPixelsFromTop) {
-        ConstraintLayout.LayoutParams layoutParams =
-            (ConstraintLayout.LayoutParams) holder.contactDisplayName.getLayoutParams();
-        layoutParams.topMargin = (int) DisplayUtils.convertDpToPixel(densityPixelsFromTop, context);
-        holder.contactDisplayName.setLayoutParams(layoutParams);
-    }
-
-    @Override
-    public boolean filter(String constraint) {
-        return participant.getDisplayName() != null &&
-            (Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getDisplayName().trim()).find() ||
-                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getActorId().trim()).find());
-    }
-
-    @Override
-    public GenericTextHeaderItem getHeader() {
-        return header;
-    }
-
-    @Override
-    public void setHeader(GenericTextHeaderItem header) {
-        this.header = header;
-    }
-
-    static class UserItemViewHolder extends FlexibleViewHolder {
-
-        @BindView(R.id.name_text)
-        public EmojiTextView contactDisplayName;
-        @Nullable
-        @BindView(R.id.avatar_drawee_view)
-        public SimpleDraweeView participantAvatar;
-        @Nullable
-        @BindView(R.id.secondary_text)
-        public EmojiTextView contactMentionId;
-        @Nullable
-        @BindView(R.id.videoCallIcon)
-        ImageView videoCallIconView;
-        @Nullable
-        @BindView(R.id.checkedImageView)
-        ImageView checkedImageView;
-        @Nullable
-        @BindView(R.id.participant_status_emoji)
-        com.vanniktech.emoji.EmojiEditText participantEmoji;
-        @Nullable
-        @BindView(R.id.user_status_image)
-        ImageView userStatusImage;
-        @Nullable
-        @BindView(R.id.conversation_info_status_message)
-        EmojiTextView statusMessage;
-
-        /**
-         * Default constructor.
-         */
-        UserItemViewHolder(View view, FlexibleAdapter adapter) {
-            super(view, adapter);
-            ButterKnife.bind(this, view);
-        }
-    }
-}

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

@@ -46,7 +46,7 @@ import android.widget.RelativeLayout;
 import com.bluelinelabs.logansquare.LoganSquare;
 import com.bluelinelabs.logansquare.LoganSquare;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.adapters.items.GenericTextHeaderItem;
 import com.nextcloud.talk.adapters.items.GenericTextHeaderItem;
-import com.nextcloud.talk.adapters.items.UserItem;
+import com.nextcloud.talk.adapters.items.ContactItem;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.controllers.base.BaseController;
@@ -550,8 +550,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                                         userHeaderItems.put(headerTitle, genericTextHeaderItem);
                                         userHeaderItems.put(headerTitle, genericTextHeaderItem);
                                     }
                                     }
 
 
-                                    UserItem newContactItem = new UserItem(
-                                        getApplicationContext(),
+                                    ContactItem newContactItem = new ContactItem(
                                         participant,
                                         participant,
                                         currentUser,
                                         currentUser,
                                         userHeaderItems.get(headerTitle)
                                         userHeaderItems.get(headerTitle)
@@ -573,21 +572,21 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                             String firstName;
                             String firstName;
                             String secondName;
                             String secondName;
 
 
-                            if (o1 instanceof UserItem) {
-                                firstName = ((UserItem) o1).getModel().getDisplayName();
+                            if (o1 instanceof ContactItem) {
+                                firstName = ((ContactItem) o1).getModel().getDisplayName();
                             } else {
                             } else {
                                 firstName = ((GenericTextHeaderItem) o1).getModel();
                                 firstName = ((GenericTextHeaderItem) o1).getModel();
                             }
                             }
 
 
-                            if (o2 instanceof UserItem) {
-                                secondName = ((UserItem) o2).getModel().getDisplayName();
+                            if (o2 instanceof ContactItem) {
+                                secondName = ((ContactItem) o2).getModel().getDisplayName();
                             } else {
                             } else {
                                 secondName = ((GenericTextHeaderItem) o2).getModel();
                                 secondName = ((GenericTextHeaderItem) o2).getModel();
                             }
                             }
 
 
-                            if (o1 instanceof UserItem && o2 instanceof UserItem) {
-                                String firstSource = ((UserItem) o1).getModel().getSource();
-                                String secondSource = ((UserItem) o2).getModel().getSource();
+                            if (o1 instanceof ContactItem && o2 instanceof ContactItem) {
+                                String firstSource = ((ContactItem) o1).getModel().getSource();
+                                String secondSource = ((ContactItem) o2).getModel().getSource();
                                 if (firstSource.equals(secondSource)) {
                                 if (firstSource.equals(secondSource)) {
                                     return firstName.compareToIgnoreCase(secondName);
                                     return firstName.compareToIgnoreCase(secondName);
                                 }
                                 }
@@ -624,24 +623,24 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                             String firstName;
                             String firstName;
                             String secondName;
                             String secondName;
 
 
-                            if (o1 instanceof UserItem) {
-                                firstName = ((UserItem) o1).getModel().getDisplayName();
+                            if (o1 instanceof ContactItem) {
+                                firstName = ((ContactItem) o1).getModel().getDisplayName();
                             } else {
                             } else {
                                 firstName = ((GenericTextHeaderItem) o1).getModel();
                                 firstName = ((GenericTextHeaderItem) o1).getModel();
                             }
                             }
 
 
-                            if (o2 instanceof UserItem) {
-                                secondName = ((UserItem) o2).getModel().getDisplayName();
+                            if (o2 instanceof ContactItem) {
+                                secondName = ((ContactItem) o2).getModel().getDisplayName();
                             } else {
                             } else {
                                 secondName = ((GenericTextHeaderItem) o2).getModel();
                                 secondName = ((GenericTextHeaderItem) o2).getModel();
                             }
                             }
 
 
-                            if (o1 instanceof UserItem && o2 instanceof UserItem) {
-                                if ("groups".equals(((UserItem) o1).getModel().getSource()) && "groups".equals(((UserItem) o2).getModel().getSource())) {
+                            if (o1 instanceof ContactItem && o2 instanceof ContactItem) {
+                                if ("groups".equals(((ContactItem) o1).getModel().getSource()) && "groups".equals(((ContactItem) o2).getModel().getSource())) {
                                     return firstName.compareToIgnoreCase(secondName);
                                     return firstName.compareToIgnoreCase(secondName);
-                                } else if ("groups".equals(((UserItem) o1).getModel().getSource())) {
+                                } else if ("groups".equals(((ContactItem) o1).getModel().getSource())) {
                                     return -1;
                                     return -1;
-                                } else if ("groups".equals(((UserItem) o2).getModel().getSource())) {
+                                } else if ("groups".equals(((ContactItem) o2).getModel().getSource())) {
                                     return 1;
                                     return 1;
                                 }
                                 }
                             }
                             }
@@ -827,12 +826,12 @@ public class ContactsController extends BaseController implements SearchView.OnQ
 
 
     @Override
     @Override
     public boolean onItemClick(View view, int position) {
     public boolean onItemClick(View view, int position) {
-        if (adapter.getItem(position) instanceof UserItem) {
+        if (adapter.getItem(position) instanceof ContactItem) {
             if (!isNewConversationView && !isAddingParticipantsView) {
             if (!isNewConversationView && !isAddingParticipantsView) {
-                UserItem userItem = (UserItem) adapter.getItem(position);
+                ContactItem contactItem = (ContactItem) adapter.getItem(position);
                 String roomType = "1";
                 String roomType = "1";
 
 
-                if ("groups".equals(userItem.getModel().getSource())) {
+                if ("groups".equals(contactItem.getModel().getSource())) {
                     roomType = "2";
                     roomType = "2";
                 }
                 }
 
 
@@ -842,7 +841,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                                                                                         currentUser.getBaseUrl(),
                                                                                         currentUser.getBaseUrl(),
                                                                                         roomType,
                                                                                         roomType,
                                                                                         null,
                                                                                         null,
-                                                                                        userItem.getModel().getActorId(),
+                                                                                        contactItem.getModel().getActorId(),
                                                                                         null);
                                                                                         null);
 
 
                 ncApi.createRoom(credentials,
                 ncApi.createRoom(credentials,
@@ -881,7 +880,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                         }
                         }
                     });
                     });
             } else {
             } else {
-                Participant participant = ((UserItem) adapter.getItem(position)).getModel();
+                Participant participant = ((ContactItem) adapter.getItem(position)).getModel();
                 participant.setSelected(!participant.isSelected());
                 participant.setSelected(!participant.isSelected());
 
 
                 if ("groups".equals(participant.getSource())) {
                 if ("groups".equals(participant.getSource())) {
@@ -912,10 +911,10 @@ public class ContactsController extends BaseController implements SearchView.OnQ
 
 
                 if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity")
                 if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity")
                     && !CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails") &&
                     && !CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails") &&
-                    "groups".equals(((UserItem) adapter.getItem(position)).getModel().getSource()) &&
+                    "groups".equals(((ContactItem) adapter.getItem(position)).getModel().getSource()) &&
                     participant.isSelected() &&
                     participant.isSelected() &&
                     adapter.getSelectedItemCount() > 1) {
                     adapter.getSelectedItemCount() > 1) {
-                    List<UserItem> currentItems = adapter.getCurrentItems();
+                    List<ContactItem> currentItems = adapter.getCurrentItems();
                     Participant internalParticipant;
                     Participant internalParticipant;
                     for (int i = 0; i < currentItems.size(); i++) {
                     for (int i = 0; i < currentItems.size(); i++) {
                         internalParticipant = currentItems.get(i).getModel();
                         internalParticipant = currentItems.get(i).getModel();
@@ -961,8 +960,8 @@ public class ContactsController extends BaseController implements SearchView.OnQ
             List<AbstractFlexibleItem> currentItems = adapter.getCurrentItems();
             List<AbstractFlexibleItem> currentItems = adapter.getCurrentItems();
             Participant internalParticipant;
             Participant internalParticipant;
             for (int i = 0; i < currentItems.size(); i++) {
             for (int i = 0; i < currentItems.size(); i++) {
-                if (currentItems.get(i) instanceof UserItem) {
-                    internalParticipant = ((UserItem) currentItems.get(i)).getModel();
+                if (currentItems.get(i) instanceof ContactItem) {
+                    internalParticipant = ((ContactItem) currentItems.get(i)).getModel();
                     if (internalParticipant.getActorType() == Participant.ActorType.GROUPS &&
                     if (internalParticipant.getActorType() == Participant.ActorType.GROUPS &&
                         internalParticipant.isSelected()) {
                         internalParticipant.isSelected()) {
                         internalParticipant.setSelected(false);
                         internalParticipant.setSelected(false);
@@ -973,10 +972,10 @@ public class ContactsController extends BaseController implements SearchView.OnQ
         }
         }
 
 
         for (int i = 0; i < adapter.getItemCount(); i++) {
         for (int i = 0; i < adapter.getItemCount(); i++) {
-            if (adapter.getItem(i) instanceof UserItem) {
-                UserItem userItem = (UserItem) adapter.getItem(i);
-                if ("groups".equals(userItem.getModel().getSource())) {
-                    userItem.setEnabled(!isPublicCall);
+            if (adapter.getItem(i) instanceof ContactItem) {
+                ContactItem contactItem = (ContactItem) adapter.getItem(i);
+                if ("groups".equals(contactItem.getModel().getSource())) {
+                    contactItem.setEnabled(!isPublicCall);
                 }
                 }
             }
             }
         }
         }

+ 11 - 10
app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt

@@ -49,7 +49,7 @@ import com.bluelinelabs.conductor.RouterTransaction
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.facebook.drawee.backends.pipeline.Fresco
 import com.facebook.drawee.backends.pipeline.Fresco
 import com.nextcloud.talk.R
 import com.nextcloud.talk.R
-import com.nextcloud.talk.adapters.items.UserItem
+import com.nextcloud.talk.adapters.items.ParticipantItem
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.controllers.base.NewBaseController
 import com.nextcloud.talk.controllers.base.NewBaseController
@@ -87,6 +87,7 @@ import io.reactivex.schedulers.Schedulers
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
 import org.greenrobot.eventbus.ThreadMode
+import java.util.ArrayList
 import java.util.Calendar
 import java.util.Calendar
 import java.util.Collections
 import java.util.Collections
 import java.util.Comparator
 import java.util.Comparator
@@ -122,8 +123,8 @@ class ConversationInfoController(args: Bundle) :
     private var databaseStorageModule: DatabaseStorageModule? = null
     private var databaseStorageModule: DatabaseStorageModule? = null
     private var conversation: Conversation? = null
     private var conversation: Conversation? = null
 
 
-    private var adapter: FlexibleAdapter<UserItem>? = null
-    private var userItems: MutableList<UserItem> = ArrayList()
+    private var adapter: FlexibleAdapter<ParticipantItem>? = null
+    private var userItems: MutableList<ParticipantItem> = ArrayList()
 
 
     private var saveStateHandler: LovelySaveStateHandler? = null
     private var saveStateHandler: LovelySaveStateHandler? = null
 
 
@@ -378,15 +379,15 @@ class ConversationInfoController(args: Bundle) :
     }
     }
 
 
     private fun handleParticipants(participants: List<Participant>) {
     private fun handleParticipants(participants: List<Participant>) {
-        var userItem: UserItem
+        var userItem: ParticipantItem
         var participant: Participant
         var participant: Participant
 
 
         userItems = ArrayList()
         userItems = ArrayList()
-        var ownUserItem: UserItem? = null
+        var ownUserItem: ParticipantItem? = null
 
 
         for (i in participants.indices) {
         for (i in participants.indices) {
             participant = participants[i]
             participant = participants[i]
-            userItem = UserItem(router.activity, participant, conversationUser, null)
+            userItem = ParticipantItem(router.activity, participant, conversationUser)
             if (participant.sessionId != null) {
             if (participant.sessionId != null) {
                 userItem.isOnline = !participant.sessionId.equals("0")
                 userItem.isOnline = !participant.sessionId.equals("0")
             } else {
             } else {
@@ -402,7 +403,7 @@ class ConversationInfoController(args: Bundle) :
             }
             }
         }
         }
 
 
-        Collections.sort(userItems, UserItemComparator())
+        Collections.sort(userItems, ParticipantItemComparator())
 
 
         if (ownUserItem != null) {
         if (ownUserItem != null) {
             userItems.add(0, ownUserItem)
             userItems.add(0, ownUserItem)
@@ -956,7 +957,7 @@ class ConversationInfoController(args: Bundle) :
             return true
             return true
         }
         }
 
 
-        val userItem = adapter?.getItem(position) as UserItem
+        val userItem = adapter?.getItem(position) as ParticipantItem
         val participant = userItem.model
         val participant = userItem.model
 
 
         val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1))
         val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1))
@@ -1108,8 +1109,8 @@ class ConversationInfoController(args: Bundle) :
     /**
     /**
      * Comparator for participants, sorts by online-status, moderator-status and display name.
      * Comparator for participants, sorts by online-status, moderator-status and display name.
      */
      */
-    class UserItemComparator : Comparator<UserItem> {
-        override fun compare(left: UserItem, right: UserItem): Int {
+    class ParticipantItemComparator : Comparator<ParticipantItem> {
+        override fun compare(left: ParticipantItem, right: ParticipantItem): Int {
             val leftIsGroup = left.model.actorType == GROUPS || left.model.actorType == CIRCLES
             val leftIsGroup = left.model.actorType == GROUPS || left.model.actorType == CIRCLES
             val rightIsGroup = right.model.actorType == GROUPS || right.model.actorType == CIRCLES
             val rightIsGroup = right.model.actorType == GROUPS || right.model.actorType == CIRCLES
             if (leftIsGroup != rightIsGroup) {
             if (leftIsGroup != rightIsGroup) {

+ 0 - 58
app/src/main/res/layout/rv_item_app.xml

@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Nextcloud Talk application
-  ~
-  ~ @author Mario Danic
-  ~ @author Andy Scherzinger
-  ~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
-  ~ Copyright (C) 2017 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/>.
-  -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="@color/bg_default"
-    android:paddingTop="16dp"
-    android:paddingBottom="16dp">
-
-    <ImageView
-        android:id="@+id/icon_image_view"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_centerVertical="true"
-        android:layout_marginStart="16dp"
-        android:contentDescription="@null"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        tools:src="@drawable/ic_add_grey600_24px" />
-
-    <TextView
-        android:id="@+id/app_title_text_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:layout_marginStart="16dp"
-        android:layout_marginEnd="16dp"
-        android:layout_toEndOf="@id/icon_image_view"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:gravity="start|center_vertical"
-        android:textAlignment="viewStart"
-        android:textColor="@color/fg_default"
-        android:textSize="16sp"
-        tools:text="Start a new conversation" />
-
-</RelativeLayout>

+ 0 - 1
app/src/main/res/layout/rv_item_conversation_info_participant.xml

@@ -26,7 +26,6 @@
     android:layout_marginBottom="@dimen/standard_half_margin"
     android:layout_marginBottom="@dimen/standard_half_margin"
     android:layout_marginTop="@dimen/standard_margin">
     android:layout_marginTop="@dimen/standard_margin">
 
 
-
     <com.facebook.drawee.view.SimpleDraweeView
     <com.facebook.drawee.view.SimpleDraweeView
         android:id="@+id/avatar_drawee_view"
         android:id="@+id/avatar_drawee_view"
         android:layout_width="@dimen/small_item_height"
         android:layout_width="@dimen/small_item_height"

+ 0 - 44
app/src/main/res/layout/rv_item_menu.xml

@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Nextcloud Talk application
-  ~
-  ~ @author Mario Danic
-  ~ @author Andy Scherzinger
-  ~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
-  ~ Copyright (C) 2018 Andy Scherzinger
-  ~
-  ~ 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/>.
-  -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="@color/bg_default"
-    android:minHeight="@dimen/bottom_sheet_item_height">
-
-    <TextView
-        android:id="@+id/menu_text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_margin="16dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false"
-        android:gravity="start|center_vertical"
-        android:textAlignment="viewStart"
-        android:textColor="@color/high_emphasis_text"
-        android:textSize="16sp"
-        tools:drawablePadding="32dp"
-        tools:drawableStart="@drawable/ic_add_grey600_24px"
-        tools:text="Start a new conversation" />
-</RelativeLayout>

+ 0 - 43
app/src/main/res/layout/rv_item_progress.xml

@@ -1,43 +0,0 @@
-<?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/>.
-  -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:padding="8dp">
-
-    <ProgressBar
-        android:id="@+id/progress_bar"
-        style="@style/Widget.AppCompat.ProgressBar"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_gravity="center" />
-
-    <TextView
-        android:id="@+id/progress_message"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:text="@string/nc_no_more_load_retry"
-        android:visibility="gone"
-        tools:visibility="visible" />
-
-</FrameLayout>

+ 0 - 12
app/src/main/res/values/strings.xml

@@ -102,9 +102,6 @@
     <string name="nc_settings_message_ringtone_key" translatable="false">message_ringtone</string>
     <string name="nc_settings_message_ringtone_key" translatable="false">message_ringtone</string>
     <string name="nc_settings_default_ringtone" translatable="false">Librem by feandesign</string>
     <string name="nc_settings_default_ringtone" translatable="false">Librem by feandesign</string>
     <string name="nc_settings_no_ringtone">No sound</string>
     <string name="nc_settings_no_ringtone">No sound</string>
-    <string name="nc_settings_vibrate">Vibrate</string>
-    <string name="nc_settings_vibrate_desc">Phone will vibrate unless it\'s silenced</string>
-    <string name="nc_settings_vibrate_key" translatable="false">notifications_vibrate</string>
 
 
     <string name="nc_settings_appearance">Appearance</string>
     <string name="nc_settings_appearance">Appearance</string>
     <string name="nc_settings_theme_title">Theme</string>
     <string name="nc_settings_theme_title">Theme</string>
@@ -329,16 +326,7 @@
     <string name="nc_remote_audio_off">Remote audio off</string>
     <string name="nc_remote_audio_off">Remote audio off</string>
     <string name="nc_add_attachment">Add attachment</string>
     <string name="nc_add_attachment">Add attachment</string>
 
 
-    <!-- Contacts endless loading -->
-    <string name="nc_no_more_load_retry">No more items to load. Refresh to retry.</string>
-    <string name="nc_endless_disabled">No more items to load (max reached).</string>
-    <string name="nc_endless_cancel">Cancelled by the user.</string>
-    <string name="nc_endless_error">An error occurred while loading more items.</string>
-
     <!-- Content descriptions -->
     <!-- Content descriptions -->
-    <string name="nc_description_more_menu_one_to_one">Menu for conversation with %1$s</string>
-    <string name="nc_description_more_menu_public">Menu for group conversation %1$s</string>
-    <string name="nc_description_more_menu_group">Menu for public conversation %1$s</string>
     <string name="nc_description_send_message_button">Send message</string>
     <string name="nc_description_send_message_button">Send message</string>
 
 
     <!-- Empty states -->
     <!-- Empty states -->

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

@@ -1 +1 @@
-492
+483

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

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