Browse Source

Migrate conversations list and next hop controllers to use the room user entity

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 2 years ago
parent
commit
7230f81cf5
47 changed files with 314 additions and 265 deletions
  1. 4 2
      app/src/main/java/com/nextcloud/talk/activities/CallActivity.java
  2. 1 1
      app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java
  3. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java
  4. 3 3
      app/src/main/java/com/nextcloud/talk/adapters/ReactionsAdapter.kt
  5. 2 4
      app/src/main/java/com/nextcloud/talk/adapters/ReactionsViewHolder.kt
  6. 1 2
      app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java
  7. 2 4
      app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.java
  8. 12 13
      app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java
  9. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java
  10. 2 2
      app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt
  11. 8 8
      app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.java
  12. 2 2
      app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java
  13. 17 11
      app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java
  14. 2 2
      app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java
  15. 27 26
      app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt
  16. 10 10
      app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt
  17. 20 16
      app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java
  18. 4 6
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.kt
  19. 5 5
      app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt
  20. 2 5
      app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt
  21. 9 9
      app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt
  22. 1 1
      app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt
  23. 4 4
      app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt
  24. 4 4
      app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsAdapter.kt
  25. 3 3
      app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsGridViewHolder.kt
  26. 3 3
      app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsListViewHolder.kt
  27. 4 4
      app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsViewHolder.kt
  28. 5 5
      app/src/main/java/com/nextcloud/talk/shareditems/viewmodels/SharedItemsViewModel.kt
  29. 3 3
      app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt
  30. 3 3
      app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt
  31. 1 2
      app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java
  32. 14 16
      app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt
  33. 6 6
      app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt
  34. 9 10
      app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt
  35. 11 0
      app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java
  36. 0 1
      app/src/main/java/com/nextcloud/talk/utils/AttendeePermissionsUtil.kt
  37. 6 3
      app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java
  38. 13 23
      app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt
  39. 35 0
      app/src/main/java/com/nextcloud/talk/utils/MimetypeUtils.kt
  40. 16 6
      app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt
  41. 5 3
      app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt
  42. 9 9
      app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.kt
  43. 4 3
      app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageFactory.java
  44. 5 5
      app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.java
  45. 5 5
      app/src/main/java/com/nextcloud/talk/utils/singletons/ApplicationWideCurrentRoomHolder.java
  46. 9 9
      app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt
  47. 1 1
      detekt.yml

+ 4 - 2
app/src/main/java/com/nextcloud/talk/activities/CallActivity.java

@@ -87,6 +87,7 @@ import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOveral
 import com.nextcloud.talk.ui.dialog.AudioOutputDialog;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
+import com.nextcloud.talk.utils.LegacyUserEntityMapper;
 import com.nextcloud.talk.utils.NotificationUtils;
 import com.nextcloud.talk.utils.animations.PulseAnimation;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
@@ -1352,7 +1353,8 @@ public class CallActivity extends CallBaseActivity {
                         ApplicationWideCurrentRoomHolder.getInstance().setSession(callSession);
                         ApplicationWideCurrentRoomHolder.getInstance().setCurrentRoomId(roomId);
                         ApplicationWideCurrentRoomHolder.getInstance().setCurrentRoomToken(roomToken);
-                        ApplicationWideCurrentRoomHolder.getInstance().setUserInRoom(conversationUser);
+                        ApplicationWideCurrentRoomHolder.getInstance().setUserInRoom(
+                            LegacyUserEntityMapper.toModel(conversationUser));
                         callOrJoinRoomViaWebSocket();
                     }
 
@@ -1415,7 +1417,7 @@ public class CallActivity extends CallBaseActivity {
 
                         if (!TextUtils.isEmpty(roomToken)) {
                             NotificationUtils.INSTANCE.cancelExistingNotificationsForRoom(getApplicationContext(),
-                                                                                          conversationUser,
+                                                                                          Objects.requireNonNull(LegacyUserEntityMapper.toModel(conversationUser)),
                                                                                           roomToken);
                         }
 

+ 1 - 1
app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java

@@ -335,7 +335,7 @@ public class CallNotificationActivity extends CallBaseActivity {
             DisplayUtils.getImageRequestForUrl(
                 ApiUtils.getUrlForAvatar(userBeingCalled.getBaseUrl(),
                                          currentConversation.getName(),
-                                         true), null);
+                                         true));
 
         ImagePipeline imagePipeline = Fresco.getImagePipeline();
         DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);

+ 1 - 1
app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java

@@ -124,7 +124,7 @@ public class ParticipantsAdapter extends BaseAdapter {
             imageView.setController(null);
             DraweeController draweeController = Fresco.newDraweeControllerBuilder()
                     .setOldController(imageView.getController())
-                    .setImageRequest(DisplayUtils.getImageRequestForUrl(participantDisplayItem.getUrlForAvatar(), null))
+                    .setImageRequest(DisplayUtils.getImageRequestForUrl(participantDisplayItem.getUrlForAvatar()))
                     .build();
             imageView.setController(draweeController);
         }

+ 3 - 3
app/src/main/java/com/nextcloud/talk/adapters/ReactionsAdapter.kt

@@ -23,18 +23,18 @@ package com.nextcloud.talk.adapters
 import android.view.LayoutInflater
 import android.view.ViewGroup
 import androidx.recyclerview.widget.RecyclerView
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ReactionItemBinding
-import com.nextcloud.talk.models.database.UserEntity
 
 class ReactionsAdapter(
     private val clickListener: ReactionItemClickListener,
-    private val userEntity: UserEntity?
+    private val user: User?
 ) : RecyclerView.Adapter<ReactionsViewHolder>() {
     internal var list: MutableList<ReactionItem> = ArrayList<ReactionItem>()
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReactionsViewHolder {
         val itemBinding = ReactionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
-        return ReactionsViewHolder(itemBinding, userEntity?.baseUrl)
+        return ReactionsViewHolder(itemBinding, user?.baseUrl)
     }
 
     override fun onBindViewHolder(holder: ReactionsViewHolder, position: Int) {

+ 2 - 4
app/src/main/java/com/nextcloud/talk/adapters/ReactionsViewHolder.kt

@@ -61,8 +61,7 @@ class ReactionsViewHolder(
                             baseUrl,
                             displayName,
                             false
-                        ),
-                        null
+                        )
                     )
                 )
                 .build()
@@ -77,8 +76,7 @@ class ReactionsViewHolder(
                             baseUrl,
                             reactionItem.reactionVoter.actorId,
                             false
-                        ),
-                        null
+                        )
                     )
                 )
                 .build()

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

@@ -141,8 +141,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
                         ApiUtils.getUrlForAvatar(
                             userEntity.getBaseUrl(),
                             participant.getCalculatedActorId(),
-                            true),
-                        null))
+                            true)))
                 .build();
             holder.binding.userIcon.setController(draweeController);
         }

+ 2 - 4
app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.java

@@ -181,8 +181,7 @@ public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemVie
                 .setImageRequest(DisplayUtils.getImageRequestForUrl(
                     ApiUtils.getUrlForGuestAvatar(userEntity.getBaseUrl(),
                                                   displayName,
-                                                  false),
-                    null))
+                                                  false)))
                 .build();
             holder.binding.avatarDraweeView.setController(draweeController);
 
@@ -194,8 +193,7 @@ public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemVie
                 .setImageRequest(DisplayUtils.getImageRequestForUrl(
                     ApiUtils.getUrlForAvatar(userEntity.getBaseUrl(),
                                              participant.getCalculatedActorId(),
-                                             false),
-                    null))
+                                             false)))
                 .build();
             holder.binding.avatarDraweeView.setController(draweeController);
         }

+ 12 - 13
app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java

@@ -35,21 +35,20 @@ import android.os.Build;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.view.View;
-import android.widget.ImageView;
 
 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.data.user.model.User;
 import com.nextcloud.talk.databinding.RvItemConversationWithLastMessageBinding;
-import com.nextcloud.talk.models.database.CapabilitiesUtil;
-import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.models.json.conversations.Conversation;
 import com.nextcloud.talk.models.json.status.Status;
 import com.nextcloud.talk.ui.StatusDrawable;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew;
 
 import java.util.List;
 import java.util.regex.Pattern;
@@ -72,23 +71,23 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
     private static final float STATUS_SIZE_IN_DP = 9f;
 
     private final Conversation conversation;
-    private final UserEntity userEntity;
+    private final User user;
     private final Context context;
     private GenericTextHeaderItem header;
     private final Status status;
 
 
-    public ConversationItem(Conversation conversation, UserEntity userEntity, Context activityContext, Status status) {
+    public ConversationItem(Conversation conversation, User user, Context activityContext, Status status) {
         this.conversation = conversation;
-        this.userEntity = userEntity;
+        this.user = user;
         this.context = activityContext;
         this.status = status;
     }
 
-    public ConversationItem(Conversation conversation, UserEntity userEntity,
+    public ConversationItem(Conversation conversation, User user,
                             Context activityContext, GenericTextHeaderItem genericTextHeaderItem, Status status) {
         this.conversation = conversation;
-        this.userEntity = userEntity;
+        this.user = user;
         this.context = activityContext;
         this.header = genericTextHeaderItem;
         this.status = status;
@@ -177,7 +176,7 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                 holder.binding.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
                 holder.binding.dialogUnreadBubble.setTextColor(Color.WHITE);
             } else if (conversation.getUnreadMention()) {
-                if (CapabilitiesUtil.hasSpreedFeatureCapability(userEntity, "direct-mention-flag")) {
+                if (CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "direct-mention-flag")) {
                     if (conversation.getUnreadMentionDirect()) {
                         holder.binding.dialogUnreadBubble.setChipBackgroundColorResource(R.color.colorPrimary);
                         holder.binding.dialogUnreadBubble.setTextColor(Color.WHITE);
@@ -233,10 +232,10 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                 holder.binding.dialogLastMessage.setText(conversation.getLastMessage().getText());
             } else {
                 String authorDisplayName = "";
-                conversation.getLastMessage().setActiveUser(userEntity);
+                conversation.getLastMessage().setActiveUser(user);
                 String text;
                 if (conversation.getLastMessage().getCalculateMessageType() == ChatMessage.MessageType.REGULAR_TEXT_MESSAGE) {
-                    if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())) {
+                    if (conversation.getLastMessage().getActorId().equals(user.getUserId())) {
                         text = String.format(appContext.getString(R.string.nc_formatted_message_you),
                                              conversation.getLastMessage().getLastMessageDisplayText());
                     } else {
@@ -305,10 +304,10 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                             .setOldController(holder.binding.dialogAvatar.getController())
                             .setAutoPlayAnimations(true)
                             .setImageRequest(DisplayUtils.getImageRequestForUrl(
-                                ApiUtils.getUrlForAvatar(userEntity.getBaseUrl(),
+                                ApiUtils.getUrlForAvatar(user.getBaseUrl(),
                                                          conversation.getName(),
                                                          false),
-                                userEntity))
+                                user))
                             .build();
                         holder.binding.dialogAvatar.setController(draweeController);
                     } else {

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

@@ -175,7 +175,7 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte
             DraweeController draweeController = Fresco.newDraweeControllerBuilder()
                 .setOldController(holder.binding.avatarDraweeView.getController())
                 .setAutoPlayAnimations(true)
-                .setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl, null))
+                .setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl))
                 .build();
             holder.binding.avatarDraweeView.setController(draweeController);
         }

+ 2 - 2
app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt

@@ -27,8 +27,8 @@ import android.view.View
 import androidx.core.content.ContextCompat
 import androidx.recyclerview.widget.RecyclerView
 import com.nextcloud.talk.R
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.RvItemSearchMessageBinding
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.domain.SearchMessageEntry
 import com.nextcloud.talk.utils.DisplayUtils
 import eu.davidea.flexibleadapter.FlexibleAdapter
@@ -40,7 +40,7 @@ import eu.davidea.viewholders.FlexibleViewHolder
 
 data class MessageResultItem constructor(
     private val context: Context,
-    private val currentUser: UserEntity,
+    private val currentUser: User,
     val messageEntry: SearchMessageEntry,
     private val showHeader: Boolean = false
 ) :

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

@@ -34,8 +34,8 @@ 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.data.user.model.User;
 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;
@@ -63,15 +63,15 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
 
     private final Context context;
     private final Participant participant;
-    private final UserEntity userEntity;
+    private final User user;
     public boolean isOnline = true;
 
     public ParticipantItem(Context activityContext,
                            Participant participant,
-                           UserEntity userEntity) {
+                           User user) {
         this.context = activityContext;
         this.participant = participant;
-        this.userEntity = userEntity;
+        this.user = user;
     }
 
     public Participant getModel() {
@@ -168,8 +168,8 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
                 .setOldController(holder.binding.avatarDraweeView.getController())
                 .setAutoPlayAnimations(true)
                 .setImageRequest(DisplayUtils.getImageRequestForUrl(
-                    ApiUtils.getUrlForGuestAvatar(userEntity.getBaseUrl(),
-                                                  displayName, false), null))
+                    ApiUtils.getUrlForGuestAvatar(user.getBaseUrl(),
+                                                  displayName, false)))
                 .build();
             holder.binding.avatarDraweeView.setController(draweeController);
 
@@ -179,8 +179,8 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
                 .setOldController(holder.binding.avatarDraweeView.getController())
                 .setAutoPlayAnimations(true)
                 .setImageRequest(DisplayUtils.getImageRequestForUrl(
-                    ApiUtils.getUrlForAvatar(userEntity.getBaseUrl(),
-                                             participant.getCalculatedActorId(), false), null))
+                    ApiUtils.getUrlForAvatar(user.getBaseUrl(),
+                                             participant.getCalculatedActorId(), false)))
                 .build();
             holder.binding.avatarDraweeView.setController(draweeController);
         }

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

@@ -46,8 +46,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
 import com.nextcloud.talk.components.filebrowser.models.DavResponse;
 import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation;
+import com.nextcloud.talk.data.user.model.User;
 import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding;
-import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet;
 import com.nextcloud.talk.utils.DisplayUtils;
@@ -288,7 +288,7 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom
         popupMenu.show();
     }
 
-    private void fetchFileInformation(String url, UserEntity activeUser) {
+    private void fetchFileInformation(String url, User activeUser) {
         Single.fromCallable(new Callable<ReadFilesystemOperation>() {
             @Override
             public ReadFilesystemOperation call() {

+ 17 - 11
app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java

@@ -29,7 +29,7 @@ import android.widget.EditText;
 
 import com.facebook.widget.text.span.BetterImageSpan;
 import com.nextcloud.talk.R;
-import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.data.user.model.User;
 import com.nextcloud.talk.models.json.mention.Mention;
 import com.nextcloud.talk.utils.DisplayUtils;
 import com.nextcloud.talk.utils.MagicCharPolicy;
@@ -40,10 +40,10 @@ import com.vanniktech.emoji.Emojis;
 
 public class MentionAutocompleteCallback implements AutocompleteCallback<Mention> {
     private Context context;
-    private UserEntity conversationUser;
+    private User conversationUser;
     private EditText editText;
 
-    public MentionAutocompleteCallback(Context context, UserEntity conversationUser,
+    public MentionAutocompleteCallback(Context context, User conversationUser,
                                        EditText editText) {
         this.context = context;
         this.conversationUser = conversationUser;
@@ -53,25 +53,31 @@ public class MentionAutocompleteCallback implements AutocompleteCallback<Mention
     @Override
     public boolean onPopupItemClicked(Editable editable, Mention item) {
         int[] range = MagicCharPolicy.getQueryRange(editable);
-        if (range == null) return false;
+        if (range == null) {
+            return false;
+        }
         int start = range[0];
         int end = range[1];
         String replacement = item.getLabel();
 
         StringBuilder replacementStringBuilder = new StringBuilder(item.getLabel());
-        for(EmojiRange emojiRange : Emojis.emojis(replacement)) {
+        for (EmojiRange emojiRange : Emojis.emojis(replacement)) {
             replacementStringBuilder.delete(emojiRange.range.getStart(), emojiRange.range.getEndInclusive());
         }
 
         editable.replace(start, end, replacementStringBuilder.toString() + " ");
         Spans.MentionChipSpan mentionChipSpan =
-                new Spans.MentionChipSpan(DisplayUtils.getDrawableForMentionChipSpan(context,
-                        item.getId(), item.getLabel(), conversationUser, item.getSource(),
-                        R.xml.chip_you, editText),
-                        BetterImageSpan.ALIGN_CENTER,
-                        item.getId(), item.getLabel());
+            new Spans.MentionChipSpan(DisplayUtils.getDrawableForMentionChipSpan(context,
+                                                                                 item.getId(),
+                                                                                 item.getLabel(),
+                                                                                 conversationUser,
+                                                                                 item.getSource(),
+                                                                                 R.xml.chip_you,
+                                                                                 editText),
+                                      BetterImageSpan.ALIGN_CENTER,
+                                      item.getId(), item.getLabel());
         editable.setSpan(mentionChipSpan, start, start + replacementStringBuilder.toString().length(),
-                Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+                         Spanned.SPAN_INCLUSIVE_INCLUSIVE);
         return true;
     }
 

+ 2 - 2
app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java

@@ -25,7 +25,7 @@ import android.util.Log;
 import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
 import com.nextcloud.talk.components.filebrowser.models.DavResponse;
 import com.nextcloud.talk.dagger.modules.RestModule;
-import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.data.user.model.User;
 import com.nextcloud.talk.utils.ApiUtils;
 
 import java.io.IOException;
@@ -47,7 +47,7 @@ public class ReadFilesystemOperation {
     private final int depth;
     private final String basePath;
 
-    public ReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) {
+    public ReadFilesystemOperation(OkHttpClient okHttpClient, User currentUser, String path, int depth) {
         OkHttpClient.Builder okHttpClientBuilder = okHttpClient.newBuilder();
         okHttpClientBuilder.followRedirects(false);
         okHttpClientBuilder.followSslRedirects(false);

+ 27 - 26
app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt

@@ -122,6 +122,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.callbacks.MentionAutocompleteCallback
 import com.nextcloud.talk.controllers.base.NewBaseController
 import com.nextcloud.talk.controllers.util.viewBinding
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ControllerChatBinding
 import com.nextcloud.talk.events.UserMentionClickEvent
 import com.nextcloud.talk.events.WebSocketCommunicationEvent
@@ -129,8 +130,6 @@ import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
 import com.nextcloud.talk.jobs.ShareOperationWorker
 import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
 import com.nextcloud.talk.messagesearch.MessageSearchActivity
-import com.nextcloud.talk.models.database.CapabilitiesUtil
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.json.chat.ChatMessage
 import com.nextcloud.talk.models.json.chat.ChatOverall
 import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage
@@ -168,6 +167,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import com.nextcloud.talk.utils.database.user.UserUtils
 import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil
 import com.nextcloud.talk.utils.rx.DisposableSet
@@ -239,7 +239,7 @@ class ChatController(args: Bundle) :
     val disposables = DisposableSet()
 
     var roomToken: String? = null
-    val conversationUser: UserEntity?
+    val conversationUser: User?
     val roomPassword: String
     var credentials: String? = null
     var currentConversation: Conversation? = null
@@ -322,7 +322,7 @@ class ChatController(args: Bundle) :
     }
 
     private fun getRoomInfo() {
-        val shouldRepeat = CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "webinary-lobby")
+        val shouldRepeat = CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "webinary-lobby")
         if (shouldRepeat) {
             checkingLobbyStatus = true
         }
@@ -656,7 +656,7 @@ class ChatController(args: Bundle) :
         })
 
         val filters = arrayOfNulls<InputFilter>(1)
-        val lengthFilter = CapabilitiesUtil.getMessageMaxLength(conversationUser) ?: MESSAGE_MAX_LENGTH
+        val lengthFilter = CapabilitiesUtilNew.getMessageMaxLength(conversationUser) ?: MESSAGE_MAX_LENGTH
 
         filters[0] = InputFilter.LengthFilter(lengthFilter)
         binding.messageInputView.inputEditText?.filters = filters
@@ -844,7 +844,7 @@ class ChatController(args: Bundle) :
 
         binding.messageInputView.button.setOnClickListener { submitMessage(false) }
 
-        if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "silent-send")) {
+        if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) {
             binding.messageInputView.button.setOnLongClickListener {
                 showSendButtonMenu()
                 true
@@ -1016,7 +1016,7 @@ class ChatController(args: Bundle) :
 
         val baseUrl = message.activeUser!!.baseUrl
         val userId = message.activeUser!!.userId
-        val attachmentFolder = CapabilitiesUtil.getAttachmentFolder(message.activeUser)
+        val attachmentFolder = CapabilitiesUtilNew.getAttachmentFolder(message.activeUser!!)
         val fileName = message.selectedIndividualHashMap!!["name"]
         var size = message.selectedIndividualHashMap!!["size"]
         if (size == null) {
@@ -1254,7 +1254,7 @@ class ChatController(args: Bundle) :
     }
 
     private fun disableCallButtons() {
-        if (CapabilitiesUtil.isAbleToCall(conversationUser)) {
+        if (CapabilitiesUtilNew.isAbleToCall(conversationUser)) {
             if (conversationVoiceCallMenuItem != null && conversationVideoMenuItem != null) {
                 conversationVoiceCallMenuItem?.icon?.alpha = SEMI_TRANSPARENT_INT
                 conversationVideoMenuItem?.icon?.alpha = SEMI_TRANSPARENT_INT
@@ -1267,7 +1267,7 @@ class ChatController(args: Bundle) :
     }
 
     private fun enableCallButtons() {
-        if (CapabilitiesUtil.isAbleToCall(conversationUser)) {
+        if (CapabilitiesUtilNew.isAbleToCall(conversationUser)) {
             if (conversationVoiceCallMenuItem != null && conversationVideoMenuItem != null) {
                 conversationVoiceCallMenuItem?.icon?.alpha = FULLY_OPAQUE_INT
                 conversationVideoMenuItem?.icon?.alpha = FULLY_OPAQUE_INT
@@ -1351,10 +1351,10 @@ class ChatController(args: Bundle) :
                 val pathList = intent?.getStringArrayListExtra(RemoteFileBrowserActivity.EXTRA_SELECTED_PATHS)
                 if (pathList?.size!! >= 1) {
                     pathList
-                        .chunked(10)
+                        .chunked(CHUNK_SIZE)
                         .forEach { paths ->
                             val data = Data.Builder()
-                                .putLong(KEY_INTERNAL_USER_ID, conversationUser!!.id)
+                                .putLong(KEY_INTERNAL_USER_ID, conversationUser!!.id!!)
                                 .putString(KEY_ROOM_TOKEN, roomToken)
                                 .putStringArray(KEY_FILE_PATHS, paths.toTypedArray())
                                 .build()
@@ -1576,7 +1576,7 @@ class ChatController(args: Bundle) :
                 .putStringArray(UploadAndShareFilesWorker.DEVICE_SOURCEFILES, files.toTypedArray())
                 .putString(
                     UploadAndShareFilesWorker.NC_TARGETPATH,
-                    CapabilitiesUtil.getAttachmentFolder(conversationUser)
+                    CapabilitiesUtilNew.getAttachmentFolder(conversationUser!!)
                 )
                 .putString(UploadAndShareFilesWorker.ROOM_TOKEN, roomToken)
                 .putString(UploadAndShareFilesWorker.META_DATA, metaData)
@@ -1656,7 +1656,7 @@ class ChatController(args: Bundle) :
                 val presenter = MentionAutocompletePresenter(activity, roomToken)
                 val callback = MentionAutocompleteCallback(
                     activity,
-                    conversationUser,
+                    conversationUser!!,
                     binding.messageInputView.inputEditText
                 )
 
@@ -1690,7 +1690,7 @@ class ChatController(args: Bundle) :
         eventBus?.register(this)
 
         if (conversationUser?.userId != "?" &&
-            CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "mention-flag") ?: false &&
+            CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "mention-flag") ?: false &&
             activity != null
         ) {
             activity?.findViewById<View>(R.id.toolbar)?.setOnClickListener { v -> showConversationInfoScreen() }
@@ -1845,7 +1845,7 @@ class ChatController(args: Bundle) :
             var apiVersion = 1
             // FIXME Fix API checking with guests?
             if (conversationUser != null) {
-                apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1))
+                apiVersion = ApiUtils.getConversationApiVersion(conversationUser!!, intArrayOf(ApiUtils.APIv4, 1))
             }
 
             val startNanoTime = System.nanoTime()
@@ -2076,9 +2076,9 @@ class ChatController(args: Bundle) :
 
     private fun setupWebsocket() {
         if (conversationUser != null) {
-            if (WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id) != null) {
+            if (WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id!!) != null) {
                 magicWebSocketInstance =
-                    WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id)
+                    WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id!!)
             } else {
                 Log.d(TAG, "magicWebSocketInstance became null")
                 magicWebSocketInstance = null
@@ -2468,7 +2468,7 @@ class ChatController(args: Bundle) :
         } else {
             conversationInfoMenuItem = menu.findItem(R.id.conversation_info)
 
-            if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) {
+            if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) {
                 conversationSharedItemsItem = menu.findItem(R.id.shared_items)
             } else {
                 menu.removeItem(R.id.shared_items)
@@ -2477,11 +2477,11 @@ class ChatController(args: Bundle) :
             loadAvatarForStatusBar()
         }
 
-        if (CapabilitiesUtil.isAbleToCall(conversationUser)) {
+        if (CapabilitiesUtilNew.isAbleToCall(conversationUser)) {
             conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call)
             conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call)
 
-            if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "silent-call")) {
+            if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-call")) {
                 Handler().post {
                     activity?.findViewById<View?>(R.id.conversation_voice_call)?.setOnLongClickListener {
                         showCallButtonMenu(true)
@@ -2505,11 +2505,11 @@ class ChatController(args: Bundle) :
     override fun onPrepareOptionsMenu(menu: Menu) {
         super.onPrepareOptionsMenu(menu)
         conversationUser?.let {
-            if (CapabilitiesUtil.hasSpreedFeatureCapability(it, "read-only-rooms")) {
+            if (CapabilitiesUtilNew.hasSpreedFeatureCapability(it, "read-only-rooms")) {
                 checkShowCallButtons()
             }
             val searchItem = menu.findItem(R.id.conversation_search)
-            searchItem.isVisible = CapabilitiesUtil.isUnifiedSearchAvailable(it)
+            searchItem.isVisible = CapabilitiesUtilNew.isUnifiedSearchAvailable(it)
         }
     }
 
@@ -2791,7 +2791,7 @@ class ChatController(args: Bundle) :
                                     Parcels.wrap(roomOverall.ocs!!.data!!)
                                 )
                                 remapChatController(
-                                    router, conversationUser!!.id,
+                                    router, conversationUser!!.id!!,
                                     roomOverall.ocs!!.data!!.token!!, bundle, true
                                 )
                             }
@@ -2942,7 +2942,7 @@ class ChatController(args: Bundle) :
     }
 
     private fun showMicrophoneButton(show: Boolean) {
-        if (show && CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "voice-message-sharing")) {
+        if (show && CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "voice-message-sharing")) {
             binding.messageInputView.messageSendButton.visibility = View.GONE
             binding.messageInputView.recordAudioButton.visibility = View.VISIBLE
         } else {
@@ -3010,7 +3010,7 @@ class ChatController(args: Bundle) :
             message.isDeleted -> false
             message.hasFileAttachment() -> false
             OBJECT_MESSAGE == message.message -> false
-            !CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "delete-messages") -> false
+            !CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "delete-messages") -> false
             !hasChatPermission -> false
             else -> true
         }
@@ -3093,7 +3093,7 @@ class ChatController(args: Bundle) :
                             conversationIntent.putExtras(bundle)
 
                             ConductorRemapping.remapChatController(
-                                router, conversationUser.id,
+                                router, conversationUser.id!!,
                                 roomOverall.ocs!!.data!!.token!!, bundle, false
                             )
                         } else {
@@ -3173,5 +3173,6 @@ class ChatController(args: Bundle) :
         private const val ANIMATION_DURATION: Long = 750
         private const val RETRIES: Long = 3
         private const val LOOKING_INTO_FUTURE_TIMEOUT = 30
+        private const val CHUNK_SIZE: Int = 10
     }
 }

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

@@ -51,7 +51,6 @@ import com.bluelinelabs.conductor.RouterTransaction
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.facebook.drawee.backends.pipeline.Fresco
 import com.nextcloud.talk.R
-import com.nextcloud.talk.shareditems.activities.SharedItemsActivity
 import com.nextcloud.talk.adapters.items.ParticipantItem
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
@@ -59,12 +58,11 @@ import com.nextcloud.talk.controllers.base.NewBaseController
 import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
 import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
 import com.nextcloud.talk.controllers.util.viewBinding
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ControllerConversationInfoBinding
 import com.nextcloud.talk.events.EventStatus
 import com.nextcloud.talk.jobs.DeleteConversationWorker
 import com.nextcloud.talk.jobs.LeaveConversationWorker
-import com.nextcloud.talk.models.database.CapabilitiesUtil
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.json.conversations.Conversation
 import com.nextcloud.talk.models.json.conversations.RoomOverall
 import com.nextcloud.talk.models.json.converters.EnumNotificationLevelConverter
@@ -74,11 +72,13 @@ import com.nextcloud.talk.models.json.participants.Participant.ActorType.CIRCLES
 import com.nextcloud.talk.models.json.participants.Participant.ActorType.GROUPS
 import com.nextcloud.talk.models.json.participants.Participant.ActorType.USERS
 import com.nextcloud.talk.models.json.participants.ParticipantsOverall
+import com.nextcloud.talk.shareditems.activities.SharedItemsActivity
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateConstants
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import com.nextcloud.talk.utils.preferences.preferencestorage.DatabaseStorageModule
 import com.yarolegovich.lovelydialog.LovelySaveStateHandler
 import com.yarolegovich.lovelydialog.LovelyStandardDialog
@@ -115,7 +115,7 @@ class ConversationInfoController(args: Bundle) :
     var eventBus: EventBus? = null
 
     private val conversationToken: String?
-    private val conversationUser: UserEntity?
+    private val conversationUser: User?
     private val hasAvatarSpacing: Boolean
     private val credentials: String?
     private var roomDisposable: Disposable? = null
@@ -134,7 +134,7 @@ class ConversationInfoController(args: Bundle) :
             if (!TextUtils.isEmpty(conversationToken) && conversationUser != null) {
                 val data = Data.Builder()
                 data.putString(BundleKeys.KEY_ROOM_TOKEN, conversationToken)
-                data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id)
+                data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id!!)
                 return data.build()
             }
 
@@ -176,7 +176,7 @@ class ConversationInfoController(args: Bundle) :
         binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog(null) }
         binding.addParticipantsAction.setOnClickListener { addParticipants() }
 
-        if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) {
+        if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) {
             binding.showSharedItemsAction.setOnClickListener { showSharedItems() }
         } else {
             binding.categorySharedItems.visibility = View.GONE
@@ -206,7 +206,7 @@ class ConversationInfoController(args: Bundle) :
     }
 
     private fun setupWebinaryView() {
-        if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "webinary-lobby") &&
+        if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "webinary-lobby") &&
             webinaryRoomType(conversation!!) &&
             conversation!!.canModerate(conversationUser!!)
         ) {
@@ -624,7 +624,7 @@ class ConversationInfoController(args: Bundle) :
 
                         if (conversationCopy!!.canModerate(conversationUser)) {
                             binding.addParticipantsAction.visibility = View.VISIBLE
-                            if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "clear-history")) {
+                            if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "clear-history")) {
                                 binding.clearConversationHistory.visibility = View.VISIBLE
                             } else {
                                 binding.clearConversationHistory.visibility = View.GONE
@@ -701,7 +701,7 @@ class ConversationInfoController(args: Bundle) :
         if (conversation != null) {
             if (
                 conversationUser != null &&
-                CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "notification-levels")
+                CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "notification-levels")
             ) {
                 binding.notificationSettingsView.conversationInfoMessageNotifications.isEnabled = true
                 binding.notificationSettingsView.conversationInfoMessageNotifications.alpha = 1.0f
@@ -730,7 +730,7 @@ class ConversationInfoController(args: Bundle) :
     private fun setProperNotificationValue(conversation: Conversation?) {
         if (conversation!!.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
             // hack to see if we get mentioned always or just on mention
-            if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "mention-flag")) {
+            if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "mention-flag")) {
                 binding.notificationSettingsView.conversationInfoMessageNotifications.value = "always"
             } else {
                 binding.notificationSettingsView.conversationInfoMessageNotifications.value = "mention"

+ 20 - 16
app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java

@@ -74,6 +74,7 @@ import com.nextcloud.talk.adapters.items.MessagesTextHeaderItem;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
+import com.nextcloud.talk.data.user.model.User;
 import com.nextcloud.talk.events.ConversationsListFetchDataEvent;
 import com.nextcloud.talk.events.EventStatus;
 import com.nextcloud.talk.interfaces.ConversationMenuInterface;
@@ -82,8 +83,6 @@ import com.nextcloud.talk.jobs.ContactAddressBookWorker;
 import com.nextcloud.talk.jobs.DeleteConversationWorker;
 import com.nextcloud.talk.jobs.UploadAndShareFilesWorker;
 import com.nextcloud.talk.messagesearch.MessageSearchHelper;
-import com.nextcloud.talk.models.database.CapabilitiesUtil;
-import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.domain.SearchMessageEntry;
 import com.nextcloud.talk.models.json.conversations.Conversation;
 import com.nextcloud.talk.models.json.status.Status;
@@ -91,6 +90,7 @@ import com.nextcloud.talk.models.json.statuses.StatusesOverall;
 import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository;
 import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment;
 import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog;
+import com.nextcloud.talk.users.UserManager;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.AttendeePermissionsUtil;
 import com.nextcloud.talk.utils.ClosedInterfaceImpl;
@@ -98,7 +98,7 @@ import com.nextcloud.talk.utils.ConductorRemapping;
 import com.nextcloud.talk.utils.DisplayUtils;
 import com.nextcloud.talk.utils.UriUtils;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
-import com.nextcloud.talk.utils.database.user.UserUtils;
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 import com.nextcloud.talk.utils.rx.SearchViewObservable;
 import com.webianks.library.PopupBubble;
@@ -162,7 +162,7 @@ public class ConversationsListController extends BaseController implements Flexi
 
     private final Bundle bundle;
     @Inject
-    UserUtils userUtils;
+    UserManager userManager;
 
     @Inject
     EventBus eventBus;
@@ -197,7 +197,7 @@ public class ConversationsListController extends BaseController implements Flexi
     @BindView(R.id.newMentionPopupBubble)
     PopupBubble newMentionPopupBubble;
 
-    private UserEntity currentUser;
+    private User currentUser;
     private Disposable roomsQueryDisposable;
     private Disposable openConversationsQueryDisposable;
     private FlexibleAdapter<AbstractFlexibleItem> adapter;
@@ -320,15 +320,15 @@ public class ConversationsListController extends BaseController implements Flexi
         if (!eventBus.isRegistered(this)) {
             eventBus.register(this);
         }
-        currentUser = userUtils.getCurrentUser();
+        currentUser = userManager.getCurrentUser().blockingGet();
 
         if (currentUser != null) {
-            if (CapabilitiesUtil.isServerEOL(currentUser)) {
+            if (CapabilitiesUtilNew.isServerEOL(currentUser)) {
                 showServerEOLDialog();
                 return;
             }
 
-            if (CapabilitiesUtil.isUnifiedSearchAvailable(currentUser)) {
+            if (CapabilitiesUtilNew.isUnifiedSearchAvailable(currentUser)) {
                 searchHelper = new MessageSearchHelper(unifiedSearchRepository);
             }
 
@@ -518,7 +518,7 @@ public class ConversationsListController extends BaseController implements Flexi
 
     @SuppressLint("LongLogTag")
     public void fetchData() {
-        if (CapabilitiesUtil.isUserStatusAvailable(userUtils.getCurrentUser())) {
+        if (CapabilitiesUtilNew.isUserStatusAvailable(userManager.getCurrentUser().blockingGet())) {
             fetchUserStatusesAndRooms();
         } else {
             fetchRooms();
@@ -682,7 +682,7 @@ public class ConversationsListController extends BaseController implements Flexi
         searchableConversationItems.clear();
         searchableConversationItems.addAll(conversationItemsWithHeader);
 
-        if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "listable-rooms")) {
+        if (CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "listable-rooms")) {
             List<AbstractFlexibleItem> openConversationItems = new ArrayList<>();
 
             openConversationsQueryDisposable = ncApi.getOpenConversations(
@@ -904,7 +904,7 @@ public class ConversationsListController extends BaseController implements Flexi
             clearMessageSearchResults();
             adapter.setFilter(filter);
             adapter.filterItems();
-            if (CapabilitiesUtil.isUnifiedSearchAvailable(currentUser)) {
+            if (CapabilitiesUtilNew.isUnifiedSearchAvailable(currentUser)) {
                 startMessageSearch(filter);
             }
         } else {
@@ -1088,7 +1088,7 @@ public class ConversationsListController extends BaseController implements Flexi
                 conversationsListBottomDialog = new ConversationsListBottomDialog(
                     getActivity(),
                     this,
-                    userUtils.getCurrentUser(),
+                    userManager.getCurrentUser().blockingGet(),
                     conversation);
                 conversationsListBottomDialog.show();
             }
@@ -1156,7 +1156,7 @@ public class ConversationsListController extends BaseController implements Flexi
                 .putStringArray(UploadAndShareFilesWorker.DEVICE_SOURCEFILES, filesToShareArray)
                 .putString(
                     UploadAndShareFilesWorker.NC_TARGETPATH,
-                    CapabilitiesUtil.getAttachmentFolder(currentUser))
+                    CapabilitiesUtilNew.getAttachmentFolder(currentUser))
                 .putString(UploadAndShareFilesWorker.ROOM_TOKEN, selectedConversation.getToken())
                 .build();
             OneTimeWorkRequest uploadWorker = new OneTimeWorkRequest.Builder(UploadAndShareFilesWorker.class)
@@ -1285,7 +1285,9 @@ public class ConversationsListController extends BaseController implements Flexi
                 .setPositiveButton(R.string.nc_delete, new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        boolean otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser.getId());
+                        boolean otherUserExists = userManager
+                            .scheduleUserForDeletionWithId(currentUser.getId())
+                            .blockingGet();
 
                         OneTimeWorkRequest accountRemovalWork = new OneTimeWorkRequest.Builder(AccountRemovalWorker.class).build();
                         WorkManager.getInstance().enqueue(accountRemovalWork);
@@ -1328,7 +1330,9 @@ public class ConversationsListController extends BaseController implements Flexi
             .setPositiveButton(R.string.nc_settings_remove_account, new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    boolean otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser.getId());
+                    boolean otherUserExists = userManager
+                        .scheduleUserForDeletionWithId(currentUser.getId())
+                        .blockingGet();
 
                     OneTimeWorkRequest accountRemovalWork = new OneTimeWorkRequest.Builder(AccountRemovalWorker.class).build();
                     WorkManager.getInstance().enqueue(accountRemovalWork);
@@ -1347,7 +1351,7 @@ public class ConversationsListController extends BaseController implements Flexi
             .setNegativeButton(R.string.nc_cancel, new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    if (userUtils.hasMultipleUsers()) {
+                    if (userManager.getUsers().blockingGet().size() > 0) {
                         getRouter().pushController(RouterTransaction.with(new SwitchAccountController()));
                     } else {
                         getActivity().finishAffinity();

+ 4 - 6
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.kt

@@ -45,10 +45,10 @@ import com.nextcloud.talk.controllers.base.NewBaseController
 import com.nextcloud.talk.controllers.util.viewBinding
 import com.nextcloud.talk.databinding.ControllerEntryMenuBinding
 import com.nextcloud.talk.models.json.conversations.Conversation
+import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.ShareUtils
 import com.nextcloud.talk.utils.UriUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
-import com.nextcloud.talk.utils.database.user.UserUtils
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
 import com.vanniktech.emoji.EmojiPopup
 import okhttp3.internal.immutableListOf
@@ -65,13 +65,11 @@ class EntryMenuController(args: Bundle) :
     ) {
     private val binding: ControllerEntryMenuBinding by viewBinding(ControllerEntryMenuBinding::bind)
 
-    @JvmField
     @Inject
-    var eventBus: EventBus? = null
+    lateinit var eventBus: EventBus
 
-    @JvmField
     @Inject
-    var userUtils: UserUtils? = null
+    lateinit var userManager: UserManager
 
     private val operation: ConversationOperationEnum
     private var conversation: Conversation? = null
@@ -271,7 +269,7 @@ class EntryMenuController(args: Bundle) :
                 ShareUtils.getStringForIntent(
                     activity,
                     binding.textEdit.text.toString(),
-                    userUtils,
+                    userManager,
                     conversation
                 )
             )

+ 5 - 5
app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt

@@ -39,11 +39,11 @@ import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
 import com.nextcloud.talk.adapters.items.MessageResultItem
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.controllers.ConversationsListController
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ActivityMessageSearchBinding
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
-import com.nextcloud.talk.utils.database.user.CurrentUserProvider
+import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
 import com.nextcloud.talk.utils.rx.SearchViewObservable.Companion.observeSearchView
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
@@ -62,12 +62,12 @@ class MessageSearchActivity : BaseActivity() {
     lateinit var viewModelFactory: ViewModelProvider.Factory
 
     @Inject
-    lateinit var userProvider: CurrentUserProvider
+    lateinit var userProvider: CurrentUserProviderNew
 
     private lateinit var binding: ActivityMessageSearchBinding
     private lateinit var searchView: SearchView
 
-    private lateinit var user: UserEntity
+    private lateinit var user: User
 
     private lateinit var viewModel: MessageSearchViewModel
 
@@ -84,7 +84,7 @@ class MessageSearchActivity : BaseActivity() {
         setContentView(binding.root)
 
         viewModel = ViewModelProvider(this, viewModelFactory)[MessageSearchViewModel::class.java]
-        user = userProvider.currentUser!!
+        user = userProvider.currentUser.blockingGet()
         val roomToken = intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!!
         viewModel.initialize(roomToken)
         setupStateObserver()

+ 2 - 5
app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt

@@ -33,7 +33,7 @@ import com.bluelinelabs.logansquare.annotation.JsonIgnore
 import com.bluelinelabs.logansquare.annotation.JsonObject
 import com.nextcloud.talk.R
 import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
-import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.json.chat.ChatUtils.Companion.getParsedMessage
 import com.nextcloud.talk.models.json.converters.EnumSystemMessageTypeConverter
 import com.nextcloud.talk.utils.ApiUtils
@@ -41,11 +41,8 @@ import com.stfalcon.chatkit.commons.models.IUser
 import com.stfalcon.chatkit.commons.models.MessageContentType
 import kotlinx.android.parcel.Parcelize
 import java.security.MessageDigest
-import java.util.ArrayList
 import java.util.Arrays
 import java.util.Date
-import java.util.HashMap
-import java.util.LinkedHashMap
 
 @Parcelize
 @JsonObject
@@ -57,7 +54,7 @@ data class ChatMessage(
     var isOneToOneConversation: Boolean = false,
 
     @JsonIgnore
-    var activeUser: UserEntity? = null,
+    var activeUser: User? = null,
 
     @JsonIgnore
     var selectedIndividualHashMap: Map<String?, String?>? = null,

+ 9 - 9
app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt

@@ -26,8 +26,7 @@ package com.nextcloud.talk.models.json.conversations
 import android.os.Parcelable
 import com.bluelinelabs.logansquare.annotation.JsonField
 import com.bluelinelabs.logansquare.annotation.JsonObject
-import com.nextcloud.talk.models.database.CapabilitiesUtil
-import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.json.chat.ChatMessage
 import com.nextcloud.talk.models.json.converters.EnumLobbyStateConverter
 import com.nextcloud.talk.models.json.converters.EnumNotificationLevelConverter
@@ -35,6 +34,7 @@ import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter
 import com.nextcloud.talk.models.json.converters.EnumReadOnlyConversationConverter
 import com.nextcloud.talk.models.json.converters.EnumRoomTypeConverter
 import com.nextcloud.talk.models.json.participants.Participant.ParticipantType
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import kotlinx.android.parcel.Parcelize
 
 @Parcelize
@@ -140,25 +140,25 @@ data class Conversation(
             ParticipantType.GUEST_MODERATOR == participantType ||
             ParticipantType.MODERATOR == participantType
 
-    private fun isLockedOneToOne(conversationUser: UserEntity): Boolean {
+    private fun isLockedOneToOne(conversationUser: User): Boolean {
         return type == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL &&
-            CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "locked-one-to-one-rooms")
+            CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "locked-one-to-one-rooms")
     }
 
-    fun canModerate(conversationUser: UserEntity): Boolean {
+    fun canModerate(conversationUser: User): Boolean {
         return isParticipantOwnerOrModerator && !isLockedOneToOne(conversationUser)
     }
 
-    fun shouldShowLobby(conversationUser: UserEntity): Boolean {
+    fun shouldShowLobby(conversationUser: User): Boolean {
         return LobbyState.LOBBY_STATE_MODERATORS_ONLY == lobbyState && !canModerate(conversationUser)
     }
 
-    fun isLobbyViewApplicable(conversationUser: UserEntity): Boolean {
+    fun isLobbyViewApplicable(conversationUser: User): Boolean {
         return !canModerate(conversationUser) &&
             (type == ConversationType.ROOM_GROUP_CALL || type == ConversationType.ROOM_PUBLIC_CALL)
     }
 
-    fun isNameEditable(conversationUser: UserEntity): Boolean {
+    fun isNameEditable(conversationUser: User): Boolean {
         return canModerate(conversationUser) && ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL != type
     }
 
@@ -171,7 +171,7 @@ data class Conversation(
         }
     }
 
-    fun canDelete(conversationUser: UserEntity): Boolean {
+    fun canDelete(conversationUser: User): Boolean {
         return if (canDeleteConversation != null) {
             // Available since APIv2
             canDeleteConversation!!

+ 1 - 1
app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt

@@ -113,7 +113,7 @@ class RemoteFileBrowserItemsListViewHolder(
             if (path.isNotEmpty()) {
                 val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
                     .setAutoPlayAnimations(true)
-                    .setImageRequest(DisplayUtils.getImageRequestForUrl(path, null))
+                    .setImageRequest(DisplayUtils.getImageRequestForUrl(path))
                     .build()
                 binding.fileIcon.controller = draweeController
             }

+ 4 - 4
app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt

@@ -36,8 +36,8 @@ import autodagger.AutoInjector
 import com.google.android.material.tabs.TabLayout
 import com.nextcloud.talk.R
 import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ActivitySharedItemsBinding
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.shareditems.adapters.SharedItemsAdapter
 import com.nextcloud.talk.shareditems.model.SharedItemType
 import com.nextcloud.talk.shareditems.viewmodels.SharedItemsViewModel
@@ -62,7 +62,7 @@ class SharedItemsActivity : AppCompatActivity() {
 
         val roomToken = intent.getStringExtra(KEY_ROOM_TOKEN)!!
         val conversationName = intent.getStringExtra(KEY_CONVERSATION_NAME)
-        val userEntity = intent.getParcelableExtra<UserEntity>(KEY_USER_ENTITY)!!
+        val user = intent.getParcelableExtra<User>(KEY_USER_ENTITY)!!
 
         binding = ActivitySharedItemsBinding.inflate(layoutInflater)
         setSupportActionBar(binding.sharedItemsToolbar)
@@ -104,7 +104,7 @@ class SharedItemsActivity : AppCompatActivity() {
                         LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
                     }
 
-                    val adapter = SharedItemsAdapter(showGrid, userEntity).apply {
+                    val adapter = SharedItemsAdapter(showGrid, user).apply {
                         items = sharedMediaItems.items
                     }
                     binding.imageRecycler.adapter = adapter
@@ -125,7 +125,7 @@ class SharedItemsActivity : AppCompatActivity() {
             }
         })
 
-        viewModel.initialize(userEntity, roomToken)
+        viewModel.initialize(user, roomToken)
     }
 
     private fun clearEmptyLoading() {

+ 4 - 4
app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsAdapter.kt

@@ -25,14 +25,14 @@ package com.nextcloud.talk.shareditems.adapters
 import android.view.LayoutInflater
 import android.view.ViewGroup
 import androidx.recyclerview.widget.RecyclerView
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.SharedItemGridBinding
 import com.nextcloud.talk.databinding.SharedItemListBinding
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.shareditems.model.SharedItem
 
 class SharedItemsAdapter(
     private val showGrid: Boolean,
-    private val userEntity: UserEntity
+    private val user: User
 ) : RecyclerView.Adapter<SharedItemsViewHolder>() {
 
     var items: List<SharedItem> = emptyList()
@@ -46,7 +46,7 @@ class SharedItemsAdapter(
                     parent,
                     false
                 ),
-                userEntity
+                user
             )
         } else {
             SharedItemsListViewHolder(
@@ -55,7 +55,7 @@ class SharedItemsAdapter(
                     parent,
                     false
                 ),
-                userEntity
+                user
             )
         }
     }

+ 3 - 3
app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsGridViewHolder.kt

@@ -25,13 +25,13 @@ package com.nextcloud.talk.shareditems.adapters
 import android.view.View
 import android.widget.ProgressBar
 import com.facebook.drawee.view.SimpleDraweeView
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.SharedItemGridBinding
-import com.nextcloud.talk.models.database.UserEntity
 
 class SharedItemsGridViewHolder(
     override val binding: SharedItemGridBinding,
-    userEntity: UserEntity
-) : SharedItemsViewHolder(binding, userEntity) {
+    user: User
+) : SharedItemsViewHolder(binding, user) {
 
     override val image: SimpleDraweeView
         get() = binding.image

+ 3 - 3
app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsListViewHolder.kt

@@ -26,15 +26,15 @@ import android.text.format.Formatter
 import android.view.View
 import android.widget.ProgressBar
 import com.facebook.drawee.view.SimpleDraweeView
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.SharedItemListBinding
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.shareditems.model.SharedItem
 import com.nextcloud.talk.utils.DateUtils
 
 class SharedItemsListViewHolder(
     override val binding: SharedItemListBinding,
-    userEntity: UserEntity
-) : SharedItemsViewHolder(binding, userEntity) {
+    user: User
+) : SharedItemsViewHolder(binding, user) {
 
     override val image: SimpleDraweeView
         get() = binding.fileImage

+ 4 - 4
app/src/main/java/com/nextcloud/talk/shareditems/adapters/SharedItemsViewHolder.kt

@@ -38,7 +38,7 @@ import com.facebook.drawee.view.SimpleDraweeView
 import com.facebook.imagepipeline.common.RotationOptions
 import com.facebook.imagepipeline.image.ImageInfo
 import com.facebook.imagepipeline.request.ImageRequestBuilder
-import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.shareditems.model.SharedItem
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DrawableUtils
@@ -46,7 +46,7 @@ import com.nextcloud.talk.utils.FileViewerUtils
 
 abstract class SharedItemsViewHolder(
     open val binding: ViewBinding,
-    private val userEntity: UserEntity
+    private val user: User
 ) : RecyclerView.ViewHolder(binding.root) {
 
     companion object {
@@ -60,7 +60,7 @@ abstract class SharedItemsViewHolder(
     private val authHeader = mapOf(
         Pair(
             "Authorization",
-            ApiUtils.getCredentials(userEntity.username, userEntity.token)
+            ApiUtils.getCredentials(user.username, user.token)
         )
     )
 
@@ -76,7 +76,7 @@ abstract class SharedItemsViewHolder(
 
         This should be done after a refactoring of FileViewerUtils.
          */
-        val fileViewerUtils = FileViewerUtils(image.context, userEntity)
+        val fileViewerUtils = FileViewerUtils(image.context, user)
 
         clickTarget.setOnClickListener {
             fileViewerUtils.openFile(

+ 5 - 5
app/src/main/java/com/nextcloud/talk/shareditems/viewmodels/SharedItemsViewModel.kt

@@ -26,7 +26,7 @@ import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
-import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.shareditems.model.SharedItemType
 import com.nextcloud.talk.shareditems.model.SharedMediaItems
 import com.nextcloud.talk.shareditems.repositories.SharedItemsRepository
@@ -57,11 +57,11 @@ class SharedItemsViewModel @Inject constructor(
     val viewState: LiveData<ViewState>
         get() = _viewState
 
-    fun initialize(userEntity: UserEntity, roomToken: String) {
+    fun initialize(user: User, roomToken: String) {
         repositoryParameters = SharedItemsRepository.Parameters(
-            userEntity.userId,
-            userEntity.token,
-            userEntity.baseUrl,
+            user.userId!!,
+            user.token!!,
+            user.baseUrl!!,
             roomToken
         )
         loadAvailableTypes()

+ 3 - 3
app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt

@@ -33,7 +33,7 @@ import com.nextcloud.talk.R
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
 import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
-import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.json.conversations.RoomOverall
 import com.nextcloud.talk.models.json.hovercard.HoverCardAction
 import com.nextcloud.talk.models.json.hovercard.HoverCardOverall
@@ -51,7 +51,7 @@ import org.parceler.Parcels
 
 private const val TAG = "ProfileBottomSheet"
 
-class ProfileBottomSheet(val ncApi: NcApi, val userEntity: UserEntity, val router: Router) {
+class ProfileBottomSheet(val ncApi: NcApi, val userEntity: User, val router: Router) {
 
     private val allowedAppIds = listOf(SPREED.stringValue, PROFILE.stringValue, EMAIL.stringValue)
 
@@ -172,7 +172,7 @@ class ProfileBottomSheet(val ncApi: NcApi, val userEntity: UserEntity, val route
                                     Parcels.wrap(roomOverall.ocs!!.data)
                                 )
                                 ConductorRemapping.remapChatController(
-                                    router, userEntity.id,
+                                    router, userEntity.id!!,
                                     roomOverall.ocs!!.data!!.token!!, bundle, true
                                 )
                             }

+ 3 - 3
app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt

@@ -31,7 +31,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
 import com.nextcloud.talk.R
 import com.nextcloud.talk.controllers.ChatController
 import com.nextcloud.talk.databinding.DialogAttachmentBinding
-import com.nextcloud.talk.models.database.CapabilitiesUtil
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 
 class AttachmentDialog(val activity: Activity, var chatController: ChatController) : BottomSheetDialog(activity) {
 
@@ -43,7 +43,7 @@ class AttachmentDialog(val activity: Activity, var chatController: ChatControlle
         setContentView(dialogAttachmentBinding.root)
         window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
 
-        var serverName = CapabilitiesUtil.getServerName(chatController.conversationUser)
+        var serverName = CapabilitiesUtilNew.getServerName(chatController.conversationUser)
         dialogAttachmentBinding.txtAttachFileFromCloud.text = chatController.resources?.let {
             if (serverName.isNullOrEmpty()) {
                 serverName = it.getString(R.string.nc_server_product_name)
@@ -51,7 +51,7 @@ class AttachmentDialog(val activity: Activity, var chatController: ChatControlle
             String.format(it.getString(R.string.nc_upload_from_cloud), serverName)
         }
 
-        if (!CapabilitiesUtil.hasSpreedFeatureCapability(
+        if (!CapabilitiesUtilNew.hasSpreedFeatureCapability(
                 chatController.conversationUser,
                 "geo-location-sharing"
             )

+ 1 - 2
app/src/main/java/com/nextcloud/talk/ui/dialog/ChooseAccountDialogFragment.java

@@ -132,8 +132,7 @@ public class ChooseAccountDialogFragment extends DialogFragment {
                         ApiUtils.getUrlForAvatar(
                             user.getBaseUrl(),
                             user.getUserId(),
-                            false),
-                        null))
+                            false)))
                     .build();
                 binding.currentAccount.userIcon.setController(draweeController);
 

+ 14 - 16
app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt

@@ -42,28 +42,28 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.controllers.ConversationsListController
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_ADD_FAVORITE
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_SET_PASSWORD
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_CLEAR_PASSWORD
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MAKE_PRIVATE
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MAKE_PUBLIC
-import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM
 import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MARK_AS_READ
+import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE
+import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM
+import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_SET_PASSWORD
 import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController
 import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.DialogConversationOperationsBinding
 import com.nextcloud.talk.jobs.LeaveConversationWorker
-import com.nextcloud.talk.models.database.CapabilitiesUtil
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.json.conversations.Conversation
+import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.Mimetype.TEXT_PLAIN
 import com.nextcloud.talk.utils.ShareUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPERATION_CODE
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
-import com.nextcloud.talk.utils.database.user.UserUtils
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import org.parceler.Parcels
 import javax.inject.Inject
 
@@ -71,7 +71,7 @@ import javax.inject.Inject
 class ConversationsListBottomDialog(
     val activity: Activity,
     val controller: ConversationsListController,
-    val currentUser: UserEntity,
+    val currentUser: User,
     val conversation: Conversation
 ) : BottomSheetDialog(activity) {
 
@@ -80,12 +80,10 @@ class ConversationsListBottomDialog(
     private lateinit var binding: DialogConversationOperationsBinding
 
     @Inject
-    @JvmField
-    var ncApi: NcApi? = null
+    lateinit var ncApi: NcApi
 
     @Inject
-    @JvmField
-    var userUtils: UserUtils? = null
+    lateinit var userManager: UserManager
 
     init {
         NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this)
@@ -111,7 +109,7 @@ class ConversationsListBottomDialog(
     }
 
     private fun initItemsVisibility() {
-        val hasFavoritesCapability = CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "favorites")
+        val hasFavoritesCapability = CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "favorites")
         val canModerate = conversation.canModerate(currentUser)
 
         binding.conversationOperationRemoveFavorite.visibility = setVisibleIf(
@@ -122,7 +120,7 @@ class ConversationsListBottomDialog(
         )
 
         binding.conversationOperationMarkAsRead.visibility = setVisibleIf(
-            conversation.unreadMessages > 0 && CapabilitiesUtil.canSetChatReadMarker(currentUser)
+            conversation.unreadMessages > 0 && CapabilitiesUtilNew.canSetChatReadMarker(currentUser)
         )
 
         binding.conversationOperationRename.visibility = setVisibleIf(
@@ -185,7 +183,7 @@ class ConversationsListBottomDialog(
         binding.conversationOperationLeave.setOnClickListener {
             val dataBuilder = Data.Builder()
             dataBuilder.putString(KEY_ROOM_TOKEN, conversation.token)
-            dataBuilder.putLong(KEY_INTERNAL_USER_ID, currentUser.id)
+            dataBuilder.putLong(KEY_INTERNAL_USER_ID, currentUser.id!!)
             val data = dataBuilder.build()
 
             val leaveConversationWorker =
@@ -200,7 +198,7 @@ class ConversationsListBottomDialog(
         binding.conversationOperationDelete.setOnClickListener {
             if (!TextUtils.isEmpty(conversation.token)) {
                 val bundle = Bundle()
-                bundle.putLong(KEY_INTERNAL_USER_ID, currentUser.id)
+                bundle.putLong(KEY_INTERNAL_USER_ID, currentUser.id!!)
                 bundle.putParcelable(KEY_ROOM, Parcels.wrap(conversation))
 
                 controller.openLovelyDialogWithIdAndBundle(
@@ -254,7 +252,7 @@ class ConversationsListBottomDialog(
                 // password should not be shared!!
                 putExtra(
                     Intent.EXTRA_TEXT,
-                    ShareUtils.getStringForIntent(activity, null, userUtils, conversation)
+                    ShareUtils.getStringForIntent(activity, null, userManager, conversation)
                 )
             }
 

+ 6 - 6
app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt

@@ -38,13 +38,13 @@ import com.nextcloud.talk.BuildConfig
 import com.nextcloud.talk.R
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.controllers.ChatController
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.DialogMessageActionsBinding
-import com.nextcloud.talk.models.database.CapabilitiesUtil
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.json.chat.ChatMessage
 import com.nextcloud.talk.models.json.conversations.Conversation
 import com.nextcloud.talk.models.json.generic.GenericOverall
 import com.nextcloud.talk.utils.ApiUtils
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import com.vanniktech.emoji.EmojiPopup
 import com.vanniktech.emoji.EmojiTextView
 import com.vanniktech.emoji.installDisableKeyboardInput
@@ -57,7 +57,7 @@ import io.reactivex.schedulers.Schedulers
 class MessageActionsDialog(
     private val chatController: ChatController,
     private val message: ChatMessage,
-    private val user: UserEntity?,
+    private val user: User?,
     private val currentConversation: Conversation?,
     private val showMessageDeletionButton: Boolean,
     private val hasChatPermission: Boolean,
@@ -102,8 +102,8 @@ class MessageActionsDialog(
         behavior.state = BottomSheetBehavior.STATE_COLLAPSED
     }
 
-    private fun hasUserId(user: UserEntity?): Boolean {
-        return user?.userId?.isNotEmpty() == true && user?.userId != "?"
+    private fun hasUserId(user: User?): Boolean {
+        return user?.userId?.isNotEmpty() == true && user.userId != "?"
     }
 
     private fun hasUserActorId(message: ChatMessage): Boolean {
@@ -165,7 +165,7 @@ class MessageActionsDialog(
     }
 
     private fun initEmojiBar(hasChatPermission: Boolean) {
-        if (CapabilitiesUtil.hasSpreedFeatureCapability(user, "reactions") &&
+        if (CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "reactions") &&
             isPermitted(hasChatPermission) &&
             isReactableMessageType(message)
         ) {

+ 9 - 10
app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt

@@ -44,9 +44,9 @@ import com.nextcloud.talk.adapters.ReactionItemClickListener
 import com.nextcloud.talk.adapters.ReactionsAdapter
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.DialogMessageReactionsBinding
 import com.nextcloud.talk.databinding.ItemReactionsTabBinding
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.json.chat.ChatMessage
 import com.nextcloud.talk.models.json.conversations.Conversation
 import com.nextcloud.talk.models.json.generic.GenericOverall
@@ -57,14 +57,13 @@ import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.disposables.Disposable
 import io.reactivex.schedulers.Schedulers
 import java.util.Collections
-import java.util.Comparator
 
 @AutoInjector(NextcloudTalkApplication::class)
 class ShowReactionsDialog(
     activity: Activity,
     private val currentConversation: Conversation?,
     private val chatMessage: ChatMessage,
-    private val userEntity: UserEntity?,
+    private val user: User?,
     private val hasChatPermission: Boolean,
     private val ncApi: NcApi
 ) : BottomSheetDialog(activity), ReactionItemClickListener {
@@ -80,7 +79,7 @@ class ShowReactionsDialog(
         binding = DialogMessageReactionsBinding.inflate(layoutInflater)
         setContentView(binding.root)
         window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
-        adapter = ReactionsAdapter(this, userEntity)
+        adapter = ReactionsAdapter(this, user)
         binding.reactionsList.adapter = adapter
         binding.reactionsList.layoutManager = LinearLayoutManager(context)
         initEmojiReactions()
@@ -145,12 +144,12 @@ class ShowReactionsDialog(
     private fun updateParticipantsForEmoji(chatMessage: ChatMessage, emoji: String?) {
         adapter?.list?.clear()
 
-        val credentials = ApiUtils.getCredentials(userEntity?.username, userEntity?.token)
+        val credentials = ApiUtils.getCredentials(user?.username, user?.token)
 
         ncApi.getReactions(
             credentials,
             ApiUtils.getUrlForMessageReaction(
-                userEntity?.baseUrl,
+                user?.baseUrl,
                 currentConversation!!.token,
                 chatMessage.id
             ),
@@ -173,7 +172,7 @@ class ShowReactionsDialog(
                             }
                         }
 
-                        Collections.sort(reactionVoters, ReactionComparator(userEntity?.userId))
+                        Collections.sort(reactionVoters, ReactionComparator(user?.userId))
 
                         adapter?.list?.addAll(reactionVoters)
                         adapter?.notifyDataSetChanged()
@@ -193,19 +192,19 @@ class ShowReactionsDialog(
     }
 
     override fun onClick(reactionItem: ReactionItem) {
-        if (hasChatPermission && reactionItem.reactionVoter.actorId?.equals(userEntity?.userId) == true) {
+        if (hasChatPermission && reactionItem.reactionVoter.actorId?.equals(user?.userId) == true) {
             deleteReaction(chatMessage, reactionItem.reaction!!)
             dismiss()
         }
     }
 
     private fun deleteReaction(message: ChatMessage, emoji: String) {
-        val credentials = ApiUtils.getCredentials(userEntity?.username, userEntity?.token)
+        val credentials = ApiUtils.getCredentials(user?.username, user?.token)
 
         ncApi.deleteReaction(
             credentials,
             ApiUtils.getUrlForMessageReaction(
-                userEntity?.baseUrl,
+                user?.baseUrl,
                 currentConversation!!.token,
                 message.id
             ),

+ 11 - 0
app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java

@@ -32,6 +32,7 @@ import com.nextcloud.talk.data.user.model.User;
 import com.nextcloud.talk.models.RetrofitBucket;
 import com.nextcloud.talk.models.database.CapabilitiesUtil;
 import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew;
 
 import org.jetbrains.annotations.NotNull;
 
@@ -191,6 +192,16 @@ public class ApiUtils {
         throw new NoSupportedApiException();
     }
 
+    public static int getChatApiVersion(User user, int[] versions) throws NoSupportedApiException {
+        for (int version : versions) {
+            if (version == APIv1 && CapabilitiesUtilNew.hasSpreedFeatureCapability(user, "chat-v2")) {
+                // Do not question that chat-v2 capability shows the availability of api/v1/ endpoint *see no evil*
+                return version;
+            }
+        }
+        throw new NoSupportedApiException();
+    }
+
     protected static String getUrlForApi(int version, String baseUrl) {
         return baseUrl + spreedApiBase + version;
     }

+ 0 - 1
app/src/main/java/com/nextcloud/talk/utils/AttendeePermissionsUtil.kt

@@ -21,7 +21,6 @@
 package com.nextcloud.talk.utils
 
 import com.nextcloud.talk.data.user.model.User
-import com.nextcloud.talk.models.database.CapabilitiesUtil
 import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 

+ 6 - 3
app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java

@@ -297,8 +297,11 @@ public class DisplayUtils {
         return drawable;
     }
 
-    public static Drawable getDrawableForMentionChipSpan(Context context, String id, CharSequence label,
-                                                         UserEntity conversationUser, String type,
+    public static Drawable getDrawableForMentionChipSpan(Context context,
+                                                         String id,
+                                                         CharSequence label,
+                                                         User conversationUser,
+                                                         String type,
                                                          @XmlRes int chipResource,
                                                          @Nullable EditText emojiEditText) {
         ChipDrawable chip = ChipDrawable.createFromResource(context, chipResource);
@@ -369,7 +372,7 @@ public class DisplayUtils {
 
     public static Spannable searchAndReplaceWithMentionSpan(Context context, Spannable text,
                                                             String id, String label, String type,
-                                                            UserEntity conversationUser,
+                                                            User conversationUser,
                                                             @XmlRes int chipXmlRes) {
 
         Spannable spannableString = new SpannableString(text);

+ 13 - 23
app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt

@@ -42,14 +42,12 @@ import com.nextcloud.talk.activities.FullScreenImageActivity
 import com.nextcloud.talk.activities.FullScreenMediaActivity
 import com.nextcloud.talk.activities.FullScreenTextViewerActivity
 import com.nextcloud.talk.adapters.messages.MagicPreviewMessageViewHolder
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
-import com.nextcloud.talk.models.database.CapabilitiesUtil
-import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.json.chat.ChatMessage
 import com.nextcloud.talk.utils.AccountUtils.canWeOpenFilesApp
 import com.nextcloud.talk.utils.Mimetype.AUDIO_MPEG
 import com.nextcloud.talk.utils.Mimetype.AUDIO_OGG
-import com.nextcloud.talk.utils.Mimetype.AUDIO_PREFIX
 import com.nextcloud.talk.utils.Mimetype.AUDIO_WAV
 import com.nextcloud.talk.utils.Mimetype.IMAGE_GIF
 import com.nextcloud.talk.utils.Mimetype.IMAGE_JPEG
@@ -59,8 +57,12 @@ import com.nextcloud.talk.utils.Mimetype.TEXT_PLAIN
 import com.nextcloud.talk.utils.Mimetype.VIDEO_MP4
 import com.nextcloud.talk.utils.Mimetype.VIDEO_OGG
 import com.nextcloud.talk.utils.Mimetype.VIDEO_QUICKTIME
+import com.nextcloud.talk.utils.MimetypeUtils.isAudioOnly
+import com.nextcloud.talk.utils.MimetypeUtils.isGif
+import com.nextcloud.talk.utils.MimetypeUtils.isMarkdown
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACCOUNT
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FILE_ID
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
 import java.io.File
 import java.util.concurrent.ExecutionException
 
@@ -70,7 +72,7 @@ import java.util.concurrent.ExecutionException
  * Example:
  *   - SharedItemsViewHolder
  */
-class FileViewerUtils(private val context: Context, private val userEntity: UserEntity) {
+class FileViewerUtils(private val context: Context, private val user: User) {
 
     fun openFile(
         message: ChatMessage,
@@ -208,10 +210,10 @@ class FileViewerUtils(private val context: Context, private val userEntity: User
     }
 
     fun openFileInFilesApp(link: String, keyID: String) {
-        val accountString = userEntity.username + "@" +
-            userEntity.baseUrl
-                .replace("https://", "")
-                .replace("http://", "")
+        val accountString = user.username + "@" +
+            user.baseUrl
+                ?.replace("https://", "")
+                ?.replace("http://", "")
 
         if (canWeOpenFilesApp(context, accountString)) {
             val filesAppIntent = Intent(Intent.ACTION_VIEW, null)
@@ -276,18 +278,6 @@ class FileViewerUtils(private val context: Context, private val userEntity: User
         }
     }
 
-    private fun isGif(mimetype: String): Boolean {
-        return IMAGE_GIF == mimetype
-    }
-
-    private fun isMarkdown(mimetype: String): Boolean {
-        return TEXT_MARKDOWN == mimetype
-    }
-
-    private fun isAudioOnly(mimetype: String): Boolean {
-        return mimetype.startsWith(AUDIO_PREFIX)
-    }
-
     @SuppressLint("LongLogTag")
     private fun downloadFileToCache(
         fileInfo: FileInfo,
@@ -318,11 +308,11 @@ class FileViewerUtils(private val context: Context, private val userEntity: User
         }
 
         val data: Data = Data.Builder()
-            .putString(DownloadFileToCacheWorker.KEY_BASE_URL, userEntity.baseUrl)
-            .putString(DownloadFileToCacheWorker.KEY_USER_ID, userEntity.userId)
+            .putString(DownloadFileToCacheWorker.KEY_BASE_URL, user.baseUrl)
+            .putString(DownloadFileToCacheWorker.KEY_USER_ID, user.userId)
             .putString(
                 DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER,
-                CapabilitiesUtil.getAttachmentFolder(userEntity)
+                CapabilitiesUtilNew.getAttachmentFolder(user)
             )
             .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileInfo.fileName)
             .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path)

+ 35 - 0
app/src/main/java/com/nextcloud/talk/utils/MimetypeUtils.kt

@@ -0,0 +1,35 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2022 Andy Scherzinger <infoi@andy-scherzinger.de>
+ *
+ * model 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.
+ *
+ * model 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 model program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.utils
+
+object MimetypeUtils {
+    fun isGif(mimetype: String): Boolean {
+        return Mimetype.IMAGE_GIF == mimetype
+    }
+
+    fun isMarkdown(mimetype: String): Boolean {
+        return Mimetype.TEXT_MARKDOWN == mimetype
+    }
+
+    fun isAudioOnly(mimetype: String): Boolean {
+        return mimetype.startsWith(Mimetype.AUDIO_PREFIX)
+    }
+}

+ 16 - 6
app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt

@@ -41,6 +41,7 @@ import com.facebook.imagepipeline.image.CloseableBitmap
 import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor
 import com.nextcloud.talk.BuildConfig
 import com.nextcloud.talk.R
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.RingtoneSettings
 import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.utils.bundle.BundleKeys
@@ -189,7 +190,7 @@ object NotificationUtils {
 
     private inline fun scanNotifications(
         context: Context?,
-        conversationUser: UserEntity,
+        conversationUser: User,
         callback: (
             notificationManager: NotificationManager,
             statusBarNotification: StatusBarNotification,
@@ -218,13 +219,19 @@ object NotificationUtils {
     }
 
     fun cancelAllNotificationsForAccount(context: Context?, conversationUser: UserEntity) {
-        scanNotifications(context, conversationUser) { notificationManager, statusBarNotification, _ ->
+        scanNotifications(
+            context,
+            LegacyUserEntityMapper.toModel(conversationUser)!!
+        ) { notificationManager, statusBarNotification, _ ->
             notificationManager.cancel(statusBarNotification.id)
         }
     }
 
     fun cancelExistingNotificationWithId(context: Context?, conversationUser: UserEntity, notificationId: Long?) {
-        scanNotifications(context, conversationUser) { notificationManager, statusBarNotification, notification ->
+        scanNotifications(
+            context,
+            LegacyUserEntityMapper.toModel(conversationUser)!!
+        ) { notificationManager, statusBarNotification, notification ->
             if (notificationId == notification.extras.getLong(BundleKeys.KEY_NOTIFICATION_ID)) {
                 notificationManager.cancel(statusBarNotification.id)
             }
@@ -236,7 +243,10 @@ object NotificationUtils {
         conversationUser: UserEntity,
         roomTokenOrId: String
     ): StatusBarNotification? {
-        scanNotifications(context, conversationUser) { _, statusBarNotification, notification ->
+        scanNotifications(
+            context,
+            LegacyUserEntityMapper.toModel(conversationUser)!!
+        ) { _, statusBarNotification, notification ->
             if (roomTokenOrId == notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) {
                 return statusBarNotification
             }
@@ -246,7 +256,7 @@ object NotificationUtils {
 
     fun cancelExistingNotificationsForRoom(
         context: Context?,
-        conversationUser: UserEntity,
+        conversationUser: User,
         roomTokenOrId: String
     ) {
         scanNotifications(context, conversationUser) { notificationManager, statusBarNotification, notification ->
@@ -313,7 +323,7 @@ object NotificationUtils {
     fun loadAvatarSync(avatarUrl: String): IconCompat? {
         // TODO - how to handle errors here?
         var avatarIcon: IconCompat? = null
-        val imageRequest = DisplayUtils.getImageRequestForUrl(avatarUrl, null)
+        val imageRequest = DisplayUtils.getImageRequestForUrl(avatarUrl)
         val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, null)
         val closeableImageRef = DataSources.waitForFinalResult(dataSource) as CloseableReference<CloseableBitmap>?
         val bitmap = closeableImageRef?.get()?.underlyingBitmap

+ 5 - 3
app/src/main/java/com/nextcloud/talk/utils/ShareUtils.kt

@@ -22,21 +22,23 @@ package com.nextcloud.talk.utils
 import android.content.Context
 import com.nextcloud.talk.R
 import com.nextcloud.talk.models.json.conversations.Conversation
+import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.database.user.UserUtils
 
 object ShareUtils {
     fun getStringForIntent(
         context: Context?,
         password: String?,
-        userUtils: UserUtils?,
+        userManager: UserManager,
         conversation: Conversation?
     ): String {
-        val userEntity = userUtils?.currentUser
+        val userEntity = userManager.currentUser.blockingGet()
         var shareString = ""
         if (userEntity != null && context != null) {
             shareString = String.format(
                 context.resources.getString(R.string.nc_share_text),
-                userEntity.baseUrl, conversation?.token
+                userEntity.baseUrl,
+                conversation?.token
             )
             if (!password.isNullOrEmpty()) {
                 shareString += String.format(context.resources.getString(R.string.nc_share_text_pass), password)

+ 9 - 9
app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.kt

@@ -52,16 +52,15 @@ object CapabilitiesUtilNew {
     }
 
     @JvmStatic
-    fun hasSpreedFeatureCapability(user: User, capabilityName: String): Boolean {
-        if (user.capabilities?.spreedCapability?.features != null) {
+    fun hasSpreedFeatureCapability(user: User?, capabilityName: String): Boolean {
+        if (user?.capabilities?.spreedCapability?.features != null) {
             return user.capabilities!!.spreedCapability!!.features!!.contains(capabilityName)
         }
         return false
     }
 
-    fun getMessageMaxLength(user: User): Int {
-        val capabilities = user.capabilities!!
-        if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) {
+    fun getMessageMaxLength(user: User?): Int {
+        if (user?.capabilities?.spreedCapability?.config?.containsKey("chat") == true) {
             val chatConfigHashMap = user.capabilities!!.spreedCapability!!.config!!["chat"]
             if (chatConfigHashMap?.containsKey("max-length") == true) {
                 val chatSize = chatConfigHashMap["max-length"]!!.toInt()
@@ -105,6 +104,7 @@ object CapabilitiesUtilNew {
             user.capabilities?.userStatusCapability?.supportsEmoji == true
     }
 
+    @JvmStatic
     fun getAttachmentFolder(user: User): String? {
         if (user.capabilities?.spreedCapability?.config?.containsKey("attachments") == true) {
             val map = user.capabilities!!.spreedCapability!!.config!!["attachments"]
@@ -115,8 +115,8 @@ object CapabilitiesUtilNew {
         return "/Talk"
     }
 
-    fun getServerName(user: User): String? {
-        if (user.capabilities?.themingCapability != null) {
+    fun getServerName(user: User?): String? {
+        if (user?.capabilities?.themingCapability != null) {
             return user.capabilities!!.themingCapability!!.name
         }
         return ""
@@ -132,8 +132,8 @@ object CapabilitiesUtilNew {
             user.capabilities!!.provisioningCapability!!.accountPropertyScopesVersion!! > 1
     }
 
-    fun isAbleToCall(user: User): Boolean {
-        if (user.capabilities != null) {
+    fun isAbleToCall(user: User?): Boolean {
+        if (user?.capabilities != null) {
             val capabilities = user.capabilities
             return if (
                 capabilities?.spreedCapability?.config?.containsKey("call") == true &&

+ 4 - 3
app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageFactory.java

@@ -21,15 +21,16 @@
 package com.nextcloud.talk.utils.preferences.preferencestorage;
 
 import android.content.Context;
-import com.nextcloud.talk.models.database.UserEntity;
+
+import com.nextcloud.talk.data.user.model.User;
 import com.yarolegovich.mp.io.StorageModule;
 
 public class DatabaseStorageFactory implements StorageModule.Factory {
-    private UserEntity conversationUser;
+    private User conversationUser;
     private String conversationToken;
 
 
-    public DatabaseStorageFactory(UserEntity conversationUser, String conversationToken) {
+    public DatabaseStorageFactory(User conversationUser, String conversationToken) {
         this.conversationUser = conversationUser;
         this.conversationToken = conversationToken;
     }

+ 5 - 5
app/src/main/java/com/nextcloud/talk/utils/preferences/preferencestorage/DatabaseStorageModule.java

@@ -28,12 +28,12 @@ import android.util.Log;
 
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.data.user.model.User;
 import com.nextcloud.talk.models.database.ArbitraryStorageEntity;
-import com.nextcloud.talk.models.database.CapabilitiesUtil;
-import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.generic.GenericOverall;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageUtils;
+import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew;
 import com.yarolegovich.mp.io.StorageModule;
 
 import org.jetbrains.annotations.NotNull;
@@ -58,7 +58,7 @@ public class DatabaseStorageModule implements StorageModule {
     NcApi ncApi;
 
 
-    private UserEntity conversationUser;
+    private User conversationUser;
     private String conversationToken;
     private long accountIdentifier;
 
@@ -66,7 +66,7 @@ public class DatabaseStorageModule implements StorageModule {
 
     private String messageNotificationLevel;
 
-    public DatabaseStorageModule(UserEntity conversationUser, String conversationToken) {
+    public DatabaseStorageModule(User conversationUser, String conversationToken) {
         NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
 
         this.conversationUser = conversationUser;
@@ -122,7 +122,7 @@ public class DatabaseStorageModule implements StorageModule {
         if (!key.equals("message_notification_level")) {
             arbitraryStorageUtils.storeStorageSetting(accountIdentifier, key, value, conversationToken);
         } else {
-            if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "notification-levels")) {
+            if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "notification-levels")) {
                 if (!TextUtils.isEmpty(messageNotificationLevel) && !messageNotificationLevel.equals(value)) {
                     int intValue;
                     switch (value) {

+ 5 - 5
app/src/main/java/com/nextcloud/talk/utils/singletons/ApplicationWideCurrentRoomHolder.java

@@ -20,13 +20,13 @@
 
 package com.nextcloud.talk.utils.singletons;
 
-import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.data.user.model.User;
 
 public class ApplicationWideCurrentRoomHolder {
     private static final ApplicationWideCurrentRoomHolder holder = new ApplicationWideCurrentRoomHolder();
     private String currentRoomId = "";
     private String currentRoomToken = "";
-    private UserEntity userInRoom = new UserEntity();
+    private User userInRoom = new User();
     private boolean inCall = false;
     private boolean isDialing = false;
     private String session = "";
@@ -37,7 +37,7 @@ public class ApplicationWideCurrentRoomHolder {
 
     public void clear() {
         currentRoomId = "";
-        userInRoom = new UserEntity();
+        userInRoom = new User();
         inCall = false;
         isDialing = false;
         currentRoomToken = "";
@@ -60,11 +60,11 @@ public class ApplicationWideCurrentRoomHolder {
         this.currentRoomId = currentRoomId;
     }
 
-    public UserEntity getUserInRoom() {
+    public User getUserInRoom() {
         return userInRoom;
     }
 
-    public void setUserInRoom(UserEntity userInRoom) {
+    public void setUserInRoom(User userInRoom) {
         this.userInRoom = userInRoom;
     }
 

+ 9 - 9
app/src/test/java/com/nextcloud/talk/utils/ShareUtilsTest.kt

@@ -22,11 +22,11 @@ package com.nextcloud.talk.utils
 import android.content.Context
 import android.content.res.Resources
 import com.nextcloud.talk.R
-import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.json.conversations.Conversation
-import com.nextcloud.talk.utils.database.user.UserUtils
+import com.nextcloud.talk.users.UserManager
+import io.reactivex.Maybe
 import org.junit.Assert
-import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
@@ -41,10 +41,10 @@ class ShareUtilsTest {
     private val resources: Resources? = null
 
     @Mock
-    private val userUtils: UserUtils? = null
+    private val userManager: UserManager? = null
 
     @Mock
-    private val userEntity: UserEntity? = null
+    private val user: User? = null
 
     private val baseUrl = "https://my.nextcloud.com"
     private val token = "2aotbrjr"
@@ -54,8 +54,8 @@ class ShareUtilsTest {
     @Before
     fun setUp() {
         MockitoAnnotations.openMocks(this)
-        Mockito.`when`(userUtils!!.currentUser).thenReturn(userEntity)
-        Mockito.`when`(userEntity!!.baseUrl).thenReturn(baseUrl)
+        Mockito.`when`(userManager!!.currentUser).thenReturn(Maybe.just(user))
+        Mockito.`when`(user!!.baseUrl).thenReturn(baseUrl)
         Mockito.`when`(context!!.resources).thenReturn(resources)
         Mockito.`when`(resources!!.getString(R.string.nc_share_text))
             .thenReturn("Join the conversation at %1\$s/index.php/call/%2\$s")
@@ -72,7 +72,7 @@ class ShareUtilsTest {
         )
         Assert.assertEquals(
             "Intent string was not as expected",
-            expectedResult, ShareUtils.getStringForIntent(context, "", userUtils, conversation)
+            expectedResult, ShareUtils.getStringForIntent(context, "", userManager!!, conversation)
         )
     }
 
@@ -85,7 +85,7 @@ class ShareUtilsTest {
         )
         Assert.assertEquals(
             "Intent string was not as expected",
-            expectedResult, ShareUtils.getStringForIntent(context, password, userUtils, conversation)
+            expectedResult, ShareUtils.getStringForIntent(context, password, userManager!!, conversation)
         )
     }
 }

+ 1 - 1
detekt.yml

@@ -1,5 +1,5 @@
 build:
-  maxIssues: 88
+  maxIssues: 86
   weights:
     # complexity: 2
     # LongParameterList: 1