Browse Source

fix review comments

Co-authored-by: Álvaro Brey <alvaro.brey@nextcloud.com>
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 2 years ago
parent
commit
205292f9b0
19 changed files with 291 additions and 399 deletions
  1. 0 1
      app/src/androidTest/java/com/nextcloud/talk/activities/MainActivityTest.kt
  2. 6 10
      app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt
  3. 5 7
      app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStorageMapper.kt
  4. 1 1
      app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStoragesDao.kt
  5. 1 1
      app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStoragesRepository.kt
  6. 1 1
      app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStoragesRepositoryImpl.kt
  7. 18 28
      app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt
  8. 6 15
      app/src/main/java/com/nextcloud/talk/data/user/UsersDao.kt
  9. 1 17
      app/src/main/java/com/nextcloud/talk/data/user/model/UserEntity.kt
  10. 0 2
      app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt
  11. 0 2
      app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt
  12. 0 2
      app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt
  13. 1 28
      app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java
  14. 2 25
      app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java
  15. 56 0
      app/src/main/java/com/nextcloud/talk/utils/LegacyUserEntityMapper.kt
  16. 12 7
      app/src/main/java/com/nextcloud/talk/utils/database/arbitrarystorage/ArbitraryStorageUtils.java
  17. 0 229
      app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.java
  18. 154 0
      app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.kt
  19. 27 23
      app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java

+ 0 - 1
app/src/androidTest/java/com/nextcloud/talk/activities/MainActivityTest.kt

@@ -37,6 +37,5 @@ class MainActivityTest {
         assertNotNull("Error creating user", user)
 
         sut.runOnUiThread { sut.resetConversationsList() }
-        println("User: " + user!!.id + " / " + user.userId + " / " + user.baseUrl)
     }
 }

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

@@ -190,14 +190,10 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
     }
 
     private fun setupPhoneBookIntegration() {
-        if (CapabilitiesUtilNew.isPhoneBookIntegrationAvailable(currentUser)) {
-            activity!!.runOnUiThread {
-                binding.settingsPhoneBookIntegration.visibility = View.VISIBLE
-            }
+        if (CapabilitiesUtilNew.isPhoneBookIntegrationAvailable(currentUser!!)) {
+            binding.settingsPhoneBookIntegration.visibility = View.VISIBLE
         } else {
-            activity!!.runOnUiThread {
-                binding.settingsPhoneBookIntegration.visibility = View.GONE
-            }
+            binding.settingsPhoneBookIntegration.visibility = View.GONE
         }
     }
 
@@ -648,7 +644,7 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
 
     private fun setupServerAgeWarning() {
         when {
-            CapabilitiesUtilNew.isServerEOL(currentUser) -> {
+            CapabilitiesUtilNew.isServerEOL(currentUser!!) -> {
                 binding.serverAgeWarningText.setTextColor(ContextCompat.getColor((context)!!, R.color.nc_darkRed))
                 binding.serverAgeWarningText.setText(R.string.nc_settings_server_eol)
                 binding.serverAgeWarningIcon.setColorFilter(
@@ -656,7 +652,7 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
                     PorterDuff.Mode.SRC_IN
                 )
             }
-            CapabilitiesUtilNew.isServerAlmostEOL(currentUser) -> {
+            CapabilitiesUtilNew.isServerAlmostEOL(currentUser!!) -> {
                 binding.serverAgeWarningText.setTextColor(
                     ContextCompat.getColor((context)!!, R.color.nc_darkYellow)
                 )
@@ -688,7 +684,7 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
 
         if (CapabilitiesUtil.isReadStatusAvailable(userUtils.currentUser)) {
             (binding.settingsReadPrivacy.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
-                !CapabilitiesUtilNew.isReadStatusPrivate(currentUser)
+                !CapabilitiesUtilNew.isReadStatusPrivate(currentUser!!)
         } else {
             binding.settingsReadPrivacy.visibility = View.GONE
         }

+ 5 - 7
app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStorageMapper.kt

@@ -25,14 +25,12 @@ import com.nextcloud.talk.data.storage.model.ArbitraryStorageEntity
 
 object ArbitraryStorageMapper {
     fun toModel(entity: ArbitraryStorageEntity?): ArbitraryStorage? {
-        return if (entity == null) {
-            null
-        } else {
+        return entity?.let {
             ArbitraryStorage(
-                entity.accountIdentifier,
-                entity.key,
-                entity.storageObject,
-                entity.value
+                it.accountIdentifier,
+                it.key,
+                it.storageObject,
+                it.value
             )
         }
     }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStoragesDao.kt

@@ -42,7 +42,7 @@ abstract class ArbitraryStoragesDao {
     ): Maybe<ArbitraryStorageEntity>
 
     @Query("DELETE FROM ArbitraryStorage WHERE accountIdentifier = :accountIdentifier")
-    abstract suspend fun deleteArbitraryStorage(accountIdentifier: Long)
+    abstract fun deleteArbitraryStorage(accountIdentifier: Long)
 
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     abstract fun saveArbitraryStorage(arbitraryStorage: ArbitraryStorageEntity): Long

+ 1 - 1
app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStoragesRepository.kt

@@ -25,6 +25,6 @@ import io.reactivex.Maybe
 
 interface ArbitraryStoragesRepository {
     fun getStorageSetting(accountIdentifier: Long, key: String, objectString: String): Maybe<ArbitraryStorage>
-    suspend fun deleteArbitraryStorage(accountIdentifier: Long)
+    fun deleteArbitraryStorage(accountIdentifier: Long)
     fun saveArbitraryStorage(arbitraryStorage: ArbitraryStorage): Long
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/data/storage/ArbitraryStoragesRepositoryImpl.kt

@@ -35,7 +35,7 @@ class ArbitraryStoragesRepositoryImpl(private val arbitraryStoragesDao: Arbitrar
             .map { ArbitraryStorageMapper.toModel(it) }
     }
 
-    override suspend fun deleteArbitraryStorage(accountIdentifier: Long) {
+    override fun deleteArbitraryStorage(accountIdentifier: Long) {
         arbitraryStoragesDao.deleteArbitraryStorage(accountIdentifier)
     }
 

+ 18 - 28
app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt

@@ -25,21 +25,13 @@ import com.nextcloud.talk.data.user.model.UserEntity
 
 object UserMapper {
     fun toModel(entities: List<UserEntity?>?): List<User> {
-        return if (entities == null) {
-            ArrayList()
-        } else {
-            val users = ArrayList<User>()
-            for (entity in entities) {
-                users.add(toModel(entity)!!)
-            }
-            users
-        }
+        return entities?.map { user: UserEntity? ->
+            toModel(user)!!
+        } ?: emptyList()
     }
 
     fun toModel(entity: UserEntity?): User? {
-        return if (entity == null) {
-            null
-        } else {
+        return entity?.let {
             User(
                 entity.id,
                 entity.userId,
@@ -58,22 +50,20 @@ object UserMapper {
     }
 
     fun toEntity(model: User): UserEntity {
-        var UserEntity: UserEntity? = null
-        model.id?.let {
-            UserEntity = UserEntity(it, model.userId, model.username, model.baseUrl)
-        } ?: run {
-            UserEntity = UserEntity(userId = model.userId, username = model.username, baseUrl = model.baseUrl)
+        val userEntity = when (val id = model.id) {
+            null -> UserEntity(userId = model.userId, username = model.username, baseUrl = model.baseUrl)
+            else -> UserEntity(id, model.userId, model.username, model.baseUrl)
         }
-
-        UserEntity!!.token = model.token
-        UserEntity!!.displayName = model.displayName
-        UserEntity!!.pushConfigurationState = model.pushConfigurationState
-        UserEntity!!.capabilities = model.capabilities
-        UserEntity!!.clientCertificate = model.clientCertificate
-        UserEntity!!.externalSignalingServer = model.externalSignalingServer
-        UserEntity!!.current = model.current
-        UserEntity!!.scheduledForDeletion = model.scheduledForDeletion
-
-        return UserEntity!!
+        userEntity.apply {
+            token = model.token
+            displayName = model.displayName
+            pushConfigurationState = model.pushConfigurationState
+            capabilities = model.capabilities
+            clientCertificate = model.clientCertificate
+            externalSignalingServer = model.externalSignalingServer
+            current = model.current
+            scheduledForDeletion = model.scheduledForDeletion
+        }
+        return userEntity
     }
 }

+ 6 - 15
app/src/main/java/com/nextcloud/talk/data/user/UsersDao.kt

@@ -47,9 +47,6 @@ abstract class UsersDao {
     @Query("SELECT * FROM User where current = 1")
     abstract fun getActiveUserSynchronously(): UserEntity?
 
-    @Query("SELECT * FROM User WHERE current = 1")
-    abstract fun getActiveUserLiveData(): Single<UserEntity?>
-
     @Query("DELETE FROM User WHERE id = :id")
     abstract fun deleteUserWithId(id: Long)
 
@@ -122,13 +119,9 @@ abstract class UsersDao {
 
     @Transaction
     open suspend fun markUserForDeletion(id: Long): Boolean {
-        val users = getUsers().blockingGet()
-
-        for (user in users) {
-            if (user.id == id) {
-                user.current = FALSE
-                updateUser(user)
-            }
+        getUserWithId(id).blockingGet()?.let { user ->
+            user.current = FALSE
+            updateUser(user)
         }
 
         return setAnyUserAsActive()
@@ -137,14 +130,12 @@ abstract class UsersDao {
     @Transaction
     open suspend fun setAnyUserAsActive(): Boolean {
         val users = getUsers().blockingGet()
-        var result = FALSE
 
-        for (user in users) {
+        val result = users.firstOrNull()?.let { user ->
             user.current = TRUE
             updateUser(user)
-            result = TRUE
-            break
-        }
+            TRUE
+        } ?: FALSE
 
         return result
     }

+ 1 - 17
app/src/main/java/com/nextcloud/talk/data/user/model/UserEntity.kt

@@ -29,7 +29,6 @@ import androidx.room.PrimaryKey
 import com.nextcloud.talk.models.ExternalSignalingServer
 import com.nextcloud.talk.models.json.capabilities.Capabilities
 import com.nextcloud.talk.models.json.push.PushConfigurationState
-import com.nextcloud.talk.utils.ApiUtils
 import kotlinx.android.parcel.Parcelize
 import java.lang.Boolean.FALSE
 
@@ -48,19 +47,4 @@ data class UserEntity(
     @ColumnInfo(name = "externalSignalingServer") var externalSignalingServer: ExternalSignalingServer? = null,
     @ColumnInfo(name = "current") var current: Boolean = FALSE,
     @ColumnInfo(name = "scheduledForDeletion") var scheduledForDeletion: Boolean = FALSE,
-) : Parcelable {
-
-    fun hasSpreedFeatureCapability(capabilityName: String): Boolean {
-        return capabilities?.spreedCapability?.features?.contains(capabilityName) ?: false
-    }
-
-    fun canUserCreateGroupConversations(): Boolean {
-        val canCreateValue = capabilities?.spreedCapability?.config?.get("conversations")?.get("can-create")
-        canCreateValue?.let {
-            return it.toBoolean()
-        }
-        return true
-    }
-
-    fun getCredentials(): String = ApiUtils.getCredentials(username, token)
-}
+) : Parcelable

+ 0 - 2
app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt

@@ -25,11 +25,9 @@ import android.os.Parcelable
 import com.bluelinelabs.logansquare.annotation.JsonField
 import com.bluelinelabs.logansquare.annotation.JsonObject
 import kotlinx.android.parcel.Parcelize
-import kotlinx.serialization.Serializable
 
 @Parcelize
 @JsonObject
-@Serializable
 data class ExternalSignalingServer(
     @JsonField(name = ["externalSignalingServer"])
     var externalSignalingServer: String? = null,

+ 0 - 2
app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt

@@ -25,11 +25,9 @@ import android.os.Parcelable
 import com.bluelinelabs.logansquare.annotation.JsonField
 import com.bluelinelabs.logansquare.annotation.JsonObject
 import kotlinx.android.parcel.Parcelize
-import kotlinx.serialization.Serializable
 
 @Parcelize
 @JsonObject
-@Serializable
 data class Capabilities(
     @JsonField(name = ["spreed"])
     var spreedCapability: SpreedCapability?,

+ 0 - 2
app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt

@@ -25,11 +25,9 @@ import android.os.Parcelable
 import com.bluelinelabs.logansquare.annotation.JsonField
 import com.bluelinelabs.logansquare.annotation.JsonObject
 import kotlinx.android.parcel.Parcelize
-import kotlinx.serialization.Serializable
 
 @Parcelize
 @JsonObject
-@Serializable
 data class PushConfigurationState(
     @JsonField(name = ["pushToken"])
     var pushToken: String?,

+ 1 - 28
app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java

@@ -157,34 +157,7 @@ public class ApiUtils {
 
     @Deprecated
     public static int getConversationApiVersion(UserEntity user, int[] versions) throws NoSupportedApiException {
-        boolean hasApiV4 = false;
-        for (int version : versions) {
-            hasApiV4 |= version == APIv4;
-        }
-
-        if (!hasApiV4) {
-            Exception e = new Exception("Api call did not try conversation-v4 api");
-            Log.d(TAG, e.getMessage(), e);
-        }
-
-        for (int version : versions) {
-            if (CapabilitiesUtil.hasSpreedFeatureCapability(user, "conversation-v" + version)) {
-                return version;
-            }
-
-            // Fallback for old API versions
-            if ((version == APIv1 || version == APIv2)) {
-                if (CapabilitiesUtil.hasSpreedFeatureCapability(user, "conversation-v2")) {
-                    return version;
-                }
-                if (version == APIv1  &&
-                        CapabilitiesUtil.hasSpreedFeatureCapability(user, "mention-flag") &&
-                        !CapabilitiesUtil.hasSpreedFeatureCapability(user, "conversation-v4")) {
-                    return version;
-                }
-            }
-        }
-        throw new NoSupportedApiException();
+        return getConversationApiVersion(LegacyUserEntityMapper.toModel(user), versions);
     }
 
     public static int getSignalingApiVersion(UserEntity user, int[] versions) throws NoSupportedApiException {

+ 2 - 25
app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java

@@ -93,6 +93,7 @@ import java.text.DateFormat;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -572,31 +573,7 @@ public class DisplayUtils {
 
     @Deprecated
     public static void loadAvatarImage(UserEntity user, SimpleDraweeView avatarImageView, boolean deleteCache) {
-        String avatarId;
-        if (!TextUtils.isEmpty(user.getUserId())) {
-            avatarId = user.getUserId();
-        } else {
-            avatarId = user.getUsername();
-        }
-
-        String avatarString = ApiUtils.getUrlForAvatar(user.getBaseUrl(), avatarId, true);
-
-        // clear cache
-        if (deleteCache) {
-            Uri avatarUri = Uri.parse(avatarString);
-
-            ImagePipeline imagePipeline = Fresco.getImagePipeline();
-            imagePipeline.evictFromMemoryCache(avatarUri);
-            imagePipeline.evictFromDiskCache(avatarUri);
-            imagePipeline.evictFromCache(avatarUri);
-        }
-
-        DraweeController draweeController = Fresco.newDraweeControllerBuilder()
-            .setOldController(avatarImageView.getController())
-            .setAutoPlayAnimations(true)
-            .setImageRequest(DisplayUtils.getImageRequestForUrl(avatarString, null))
-            .build();
-        avatarImageView.setController(draweeController);
+        loadAvatarImage(Objects.requireNonNull(LegacyUserEntityMapper.toModel(user)), avatarImageView, deleteCache);
     }
 
     public static void loadAvatarImage(User user, SimpleDraweeView avatarImageView, boolean deleteCache) {

+ 56 - 0
app/src/main/java/com/nextcloud/talk/utils/LegacyUserEntityMapper.kt

@@ -0,0 +1,56 @@
+/*
+ * 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
+
+import com.bluelinelabs.logansquare.LoganSquare
+import com.nextcloud.talk.data.user.model.User
+import com.nextcloud.talk.models.ExternalSignalingServer
+import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.models.json.capabilities.Capabilities
+import com.nextcloud.talk.models.json.push.PushConfigurationState
+
+object LegacyUserEntityMapper {
+    fun toModel(entities: List<UserEntity?>?): List<User> {
+        return entities?.map { user: UserEntity? ->
+            toModel(user)!!
+        } ?: emptyList()
+    }
+
+    @JvmStatic
+    fun toModel(entity: UserEntity?): User? {
+        return entity?.let {
+            User(
+                entity.id,
+                entity.userId,
+                entity.username,
+                entity.baseUrl,
+                entity.token,
+                entity.displayName,
+                LoganSquare.parse(entity.pushConfigurationState, PushConfigurationState::class.java),
+                LoganSquare.parse(entity.capabilities, Capabilities::class.java),
+                entity.clientCertificate,
+                LoganSquare.parse(entity.externalSignalingServer, ExternalSignalingServer::class.java),
+                entity.current,
+                entity.scheduledForDeletion
+            )
+        }
+    }
+}

+ 12 - 7
app/src/main/java/com/nextcloud/talk/utils/database/arbitrarystorage/ArbitraryStorageUtils.java

@@ -20,8 +20,10 @@
 package com.nextcloud.talk.utils.database.arbitrarystorage;
 
 import androidx.annotation.Nullable;
+
 import com.nextcloud.talk.models.database.ArbitraryStorage;
 import com.nextcloud.talk.models.database.ArbitraryStorageEntity;
+
 import io.reactivex.Observable;
 import io.reactivex.schedulers.Schedulers;
 import io.requery.Persistable;
@@ -29,6 +31,9 @@ import io.requery.query.Result;
 import io.requery.reactivex.ReactiveEntityStore;
 import io.requery.reactivex.ReactiveScalar;
 
+/**
+ * @deprecated use {@link com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager} instead.
+ */
 @Deprecated
 public class ArbitraryStorageUtils {
     private ReactiveEntityStore<Persistable> dataStore;
@@ -46,16 +51,16 @@ public class ArbitraryStorageUtils {
         arbitraryStorageEntity.setObject(object);
 
         dataStore.upsert(arbitraryStorageEntity)
-                .toObservable()
-                .subscribeOn(Schedulers.io())
-                .subscribe();
+            .toObservable()
+            .subscribeOn(Schedulers.io())
+            .subscribe();
     }
 
     public ArbitraryStorageEntity getStorageSetting(long accountIdentifier, String key, @Nullable String object) {
         Result findStorageQueryResult = dataStore.select(ArbitraryStorage.class)
-                .where(ArbitraryStorageEntity.ACCOUNT_IDENTIFIER.eq(accountIdentifier)
-                        .and(ArbitraryStorageEntity.KEY.eq(key)).and(ArbitraryStorageEntity.OBJECT.eq(object)))
-                .limit(1).get();
+            .where(ArbitraryStorageEntity.ACCOUNT_IDENTIFIER.eq(accountIdentifier)
+                       .and(ArbitraryStorageEntity.KEY.eq(key)).and(ArbitraryStorageEntity.OBJECT.eq(object)))
+            .limit(1).get();
 
         return (ArbitraryStorageEntity) findStorageQueryResult.firstOrNull();
     }
@@ -64,6 +69,6 @@ public class ArbitraryStorageUtils {
         ReactiveScalar<Integer> deleteResult = dataStore.delete(ArbitraryStorage.class).where(ArbitraryStorageEntity.ACCOUNT_IDENTIFIER.eq(accountIdentifier)).get();
 
         return deleteResult.single().toObservable()
-                .subscribeOn(Schedulers.io());
+            .subscribeOn(Schedulers.io());
     }
 }

+ 0 - 229
app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesUtilNew.java

@@ -1,229 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Andy Scherzinger
- * @author Mario Danic
- * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de)
- * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package com.nextcloud.talk.utils.database.user;
-
-import com.nextcloud.talk.data.user.model.User;
-import com.nextcloud.talk.models.json.capabilities.Capabilities;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import androidx.annotation.Nullable;
-
-public abstract class CapabilitiesUtilNew {
-
-    public static boolean hasNotificationsCapability(@Nullable User user, String capabilityName) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities.getNotificationsCapability() != null &&
-                capabilities.getNotificationsCapability().getFeatures() != null) {
-                return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
-            }
-        }
-        return false;
-    }
-
-    public static boolean hasExternalCapability(@Nullable User user, String capabilityName) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities.getExternalCapability() != null &&
-                capabilities.getExternalCapability().containsKey("v1")) {
-                return capabilities.getExternalCapability().get("v1").contains(capabilityName);
-            }
-        }
-        return false;
-    }
-
-    public static boolean isServerEOL(@Nullable User user) {
-        // Capability is available since Talk 4 => Nextcloud 14 => Autmn 2018
-        return !hasSpreedFeatureCapability(user, "no-ping");
-    }
-
-    public static boolean isServerAlmostEOL(@Nullable User user) {
-        // Capability is available since Talk 8 => Nextcloud 18 => January 2020
-        return !hasSpreedFeatureCapability(user, "chat-replies");
-    }
-
-    public static boolean canSetChatReadMarker(@Nullable User user) {
-        return hasSpreedFeatureCapability(user, "chat-read-marker");
-    }
-
-    public static boolean hasSpreedFeatureCapability(@Nullable User user, String capabilityName) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities != null && capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getFeatures() != null) {
-                return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
-            }
-        }
-        return false;
-    }
-
-    public static Integer getMessageMaxLength(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities != null &&
-                capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getConfig() != null &&
-                capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
-                HashMap<String, String> chatConfigHashMap = capabilities
-                    .getSpreedCapability()
-                    .getConfig()
-                    .get("chat");
-                if (chatConfigHashMap != null && chatConfigHashMap.containsKey("max-length")) {
-                    int chatSize = Integer.parseInt(chatConfigHashMap.get("max-length"));
-                    if (chatSize > 0) {
-                        return chatSize;
-                    } else {
-                        return 1000;
-                    }
-                }
-            }
-        }
-        return 1000;
-    }
-
-    public static boolean isPhoneBookIntegrationAvailable(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            return capabilities != null &&
-                capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getFeatures() != null &&
-                capabilities.getSpreedCapability().getFeatures().contains("phonebook-search");
-        }
-        return false;
-    }
-
-    public static boolean isReadStatusAvailable(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities != null &&
-                capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getConfig() != null &&
-                capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
-                Map<String, String> map = capabilities.getSpreedCapability().getConfig().get("chat");
-                return map != null && map.containsKey("read-privacy");
-            }
-        }
-        return false;
-    }
-
-    public static boolean isReadStatusPrivate(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities != null &&
-                capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getConfig() != null &&
-                capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
-                HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("chat");
-                if (map != null && map.containsKey("read-privacy")) {
-                    return Integer.parseInt(map.get("read-privacy")) == 1;
-                }
-            }
-        }
-        return false;
-    }
-
-    public static boolean isUserStatusAvailable(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities.getUserStatusCapability() != null &&
-                capabilities.getUserStatusCapability().getEnabled() &&
-                capabilities.getUserStatusCapability().getSupportsEmoji()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static String getAttachmentFolder(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities != null &&
-                capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getConfig() != null &&
-                capabilities.getSpreedCapability().getConfig().containsKey("attachments")) {
-                HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("attachments");
-                if (map != null && map.containsKey("folder")) {
-                    return map.get("folder");
-                }
-            }
-        }
-        return "/Talk";
-    }
-
-    public static String getServerName(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities != null && capabilities.getThemingCapability() != null) {
-                return capabilities.getThemingCapability().getName();
-            }
-        }
-        return "";
-    }
-
-    // TODO later avatar can also be checked via user fields, for now it is in Talk capability
-    public static boolean isAvatarEndpointAvailable(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            return (capabilities != null &&
-                capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getFeatures() != null &&
-                capabilities.getSpreedCapability().getFeatures().contains("temp-user-avatar-api"));
-        }
-        return false;
-    }
-
-    public static boolean canEditScopes(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            return (capabilities != null &&
-                capabilities.getProvisioningCapability() != null &&
-                capabilities.getProvisioningCapability().getAccountPropertyScopesVersion() != null &&
-                capabilities.getProvisioningCapability().getAccountPropertyScopesVersion() > 1);
-        }
-        return false;
-    }
-
-    public static boolean isAbleToCall(@Nullable User user) {
-        if (user != null && user.getCapabilities() != null) {
-            Capabilities capabilities = user.getCapabilities();
-            if (capabilities != null &&
-                capabilities.getSpreedCapability() != null &&
-                capabilities.getSpreedCapability().getConfig() != null &&
-                capabilities.getSpreedCapability().getConfig().containsKey("call") &&
-                capabilities.getSpreedCapability().getConfig().get("call") != null &&
-                capabilities.getSpreedCapability().getConfig().get("call").containsKey("enabled")) {
-                return Boolean.parseBoolean(
-                    capabilities.getSpreedCapability().getConfig().get("call").get("enabled"));
-            } else {
-                // older nextcloud versions without the capability can't disable the calls
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static boolean isUnifiedSearchAvailable(@Nullable final User user) {
-        return hasSpreedFeatureCapability(user, "unified-search");
-    }
-}

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

@@ -0,0 +1,154 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Andy Scherzinger
+ * @author Mario Danic
+ * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de)
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.utils.database.user
+
+import com.nextcloud.talk.data.user.model.User
+
+@Suppress("TooManyFunctions")
+object CapabilitiesUtilNew {
+    fun hasNotificationsCapability(user: User, capabilityName: String): Boolean {
+        return user.capabilities?.spreedCapability?.features?.contains(capabilityName) == true
+    }
+
+    fun hasExternalCapability(user: User, capabilityName: String?): Boolean {
+        if (user.capabilities?.externalCapability?.containsKey("v1") == true) {
+            return user.capabilities!!.externalCapability!!["v1"]?.contains(capabilityName!!) == true
+        }
+        return false
+    }
+
+    fun isServerEOL(user: User): Boolean {
+        // Capability is available since Talk 4 => Nextcloud 14 => Autmn 2018
+        return !hasSpreedFeatureCapability(user, "no-ping")
+    }
+
+    fun isServerAlmostEOL(user: User): Boolean {
+        // Capability is available since Talk 8 => Nextcloud 18 => January 2020
+        return !hasSpreedFeatureCapability(user, "chat-replies")
+    }
+
+    fun canSetChatReadMarker(user: User): Boolean {
+        return hasSpreedFeatureCapability(user, "chat-read-marker")
+    }
+
+    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) {
+            val chatConfigHashMap = user.capabilities!!.spreedCapability!!.config!!["chat"]
+            if (chatConfigHashMap?.containsKey("max-length") == true) {
+                val chatSize = chatConfigHashMap["max-length"]!!.toInt()
+                return if (chatSize > 0) {
+                    chatSize
+                } else {
+                    DEFAULT_CHAT_SIZE
+                }
+            }
+        }
+
+        return DEFAULT_CHAT_SIZE
+    }
+
+    fun isPhoneBookIntegrationAvailable(user: User): Boolean {
+        return user.capabilities?.spreedCapability?.features?.contains("phonebook-search") == true
+    }
+
+    fun isReadStatusAvailable(user: User): Boolean {
+        if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) {
+            val map: Map<String, String>? = user.capabilities!!.spreedCapability!!.config!!["chat"]
+            return map != null && map.containsKey("read-privacy")
+        }
+        return false
+    }
+
+    fun isReadStatusPrivate(user: User): Boolean {
+        if (user.capabilities?.spreedCapability?.config?.containsKey("chat") == true) {
+            val map = user.capabilities!!.spreedCapability!!.config!!["chat"]
+            if (map?.containsKey("read-privacy") == true) {
+                return map["read-privacy"]!!.toInt() == 1
+            }
+        }
+
+        return false
+    }
+
+    fun isUserStatusAvailable(user: User): Boolean {
+        return user.capabilities?.userStatusCapability?.enabled == true &&
+            user.capabilities?.userStatusCapability?.supportsEmoji == true
+    }
+
+    fun getAttachmentFolder(user: User): String? {
+        if (user.capabilities?.spreedCapability?.config?.containsKey("attachments") == true) {
+            val map = user.capabilities!!.spreedCapability!!.config!!["attachments"]
+            if (map?.containsKey("folder") == true) {
+                return map["folder"]
+            }
+        }
+        return "/Talk"
+    }
+
+    fun getServerName(user: User): String? {
+        if (user.capabilities?.themingCapability != null) {
+            return user.capabilities!!.themingCapability!!.name
+        }
+        return ""
+    }
+
+    // TODO later avatar can also be checked via user fields, for now it is in Talk capability
+    fun isAvatarEndpointAvailable(user: User): Boolean {
+        return user.capabilities?.spreedCapability?.features?.contains("temp-user-avatar-api") == true
+    }
+
+    fun canEditScopes(user: User): Boolean {
+        return user.capabilities?.provisioningCapability?.accountPropertyScopesVersion != null &&
+            user.capabilities!!.provisioningCapability!!.accountPropertyScopesVersion!! > 1
+    }
+
+    fun isAbleToCall(user: User): Boolean {
+        if (user.capabilities != null) {
+            val capabilities = user.capabilities
+            return if (
+                capabilities?.spreedCapability?.config?.containsKey("call") == true &&
+                capabilities.spreedCapability!!.config!!["call"] != null &&
+                capabilities.spreedCapability!!.config!!["call"]!!.containsKey("enabled")
+            ) {
+                java.lang.Boolean.parseBoolean(capabilities.spreedCapability!!.config!!["call"]!!["enabled"])
+            } else {
+                // older nextcloud versions without the capability can't disable the calls
+                true
+            }
+        }
+        return false
+    }
+
+    fun isUnifiedSearchAvailable(user: User): Boolean {
+        return hasSpreedFeatureCapability(user, "unified-search")
+    }
+
+    const val DEFAULT_CHAT_SIZE = 1000
+}

+ 27 - 23
app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java

@@ -35,6 +35,9 @@ import io.requery.Persistable;
 import io.requery.query.Result;
 import io.requery.reactivex.ReactiveEntityStore;
 
+/**
+ * @deprecated use {@link com.nextcloud.talk.users.UserManager} instead.
+ */
 @Deprecated
 public class UserUtils implements CurrentUserProvider {
     private ReactiveEntityStore<Persistable> dataStore;
@@ -45,24 +48,24 @@ public class UserUtils implements CurrentUserProvider {
 
     public boolean anyUserExists() {
         return (dataStore.count(User.class).where(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE))
-                .limit(1).get().value() > 0);
+            .limit(1).get().value() > 0);
     }
 
     public boolean hasMultipleUsers() {
         return (dataStore.count(User.class).where(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE))
-                .get().value() > 1);
+            .get().value() > 1);
     }
 
     public List getUsers() {
         Result findUsersQueryResult = dataStore.select(User.class).where
-                (UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE)).get();
+            (UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE)).get();
 
         return findUsersQueryResult.toList();
     }
 
     public List getUsersScheduledForDeletion() {
         Result findUsersQueryResult = dataStore.select(User.class)
-                .where(UserEntity.SCHEDULED_FOR_DELETION.eq(Boolean.TRUE)).get();
+            .where(UserEntity.SCHEDULED_FOR_DELETION.eq(Boolean.TRUE)).get();
 
         return findUsersQueryResult.toList();
     }
@@ -70,8 +73,8 @@ public class UserUtils implements CurrentUserProvider {
 
     public UserEntity getAnyUserAndSetAsActive() {
         Result findUserQueryResult = dataStore.select(User.class)
-                .where(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE))
-                .limit(1).get();
+            .where(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE))
+            .limit(1).get();
 
         UserEntity userEntity;
         if ((userEntity = (UserEntity) findUserQueryResult.firstOrNull()) != null) {
@@ -84,10 +87,11 @@ public class UserUtils implements CurrentUserProvider {
     }
 
     @Override
-    public @Nullable UserEntity getCurrentUser() {
+    public @Nullable
+    UserEntity getCurrentUser() {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.CURRENT.eq(Boolean.TRUE)
-                .and(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE)))
-                .limit(1).get();
+                                                                            .and(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE)))
+            .limit(1).get();
 
         return (UserEntity) findUserQueryResult.firstOrNull();
     }
@@ -98,8 +102,8 @@ public class UserUtils implements CurrentUserProvider {
         UserEntity user = (UserEntity) findUserQueryResult.firstOrNull();
 
         return dataStore.delete(user)
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread());
+            .subscribeOn(Schedulers.io())
+            .observeOn(AndroidSchedulers.mainThread());
 
     }
 
@@ -109,20 +113,20 @@ public class UserUtils implements CurrentUserProvider {
         UserEntity user = (UserEntity) findUserQueryResult.firstOrNull();
 
         return dataStore.delete(user)
-                .subscribeOn(Schedulers.io());
+            .subscribeOn(Schedulers.io());
 
     }
 
     public UserEntity getUserById(String id) {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USER_ID.eq(id))
-                .limit(1).get();
+            .limit(1).get();
 
         return (UserEntity) findUserQueryResult.firstOrNull();
     }
 
     public UserEntity getUserWithId(long id) {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(id))
-                .limit(1).get();
+            .limit(1).get();
 
         return (UserEntity) findUserQueryResult.firstOrNull();
     }
@@ -140,8 +144,8 @@ public class UserUtils implements CurrentUserProvider {
 
     public boolean checkIfUserIsScheduledForDeletion(String username, String server) {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username))
-                .and(UserEntity.BASE_URL.eq(server))
-                .limit(1).get();
+            .and(UserEntity.BASE_URL.eq(server))
+            .limit(1).get();
 
         UserEntity userEntity;
         if ((userEntity = (UserEntity) findUserQueryResult.firstOrNull()) != null) {
@@ -153,23 +157,23 @@ public class UserUtils implements CurrentUserProvider {
 
     public UserEntity getUserWithInternalId(long internalId) {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(internalId)
-                .and(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE)))
-                .limit(1).get();
+                                                                            .and(UserEntity.SCHEDULED_FOR_DELETION.notEqual(Boolean.TRUE)))
+            .limit(1).get();
 
         return (UserEntity) findUserQueryResult.firstOrNull();
     }
 
     public boolean getIfUserWithUsernameAndServer(String username, String server) {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username)
-                .and(UserEntity.BASE_URL.eq(server)))
-                .limit(1).get();
+                                                                            .and(UserEntity.BASE_URL.eq(server)))
+            .limit(1).get();
 
         return findUserQueryResult.firstOrNull() != null;
     }
 
     public boolean scheduleUserForDeletionWithId(long id) {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(id))
-                .limit(1).get();
+            .limit(1).get();
 
         UserEntity userEntity;
         if ((userEntity = (UserEntity) findUserQueryResult.firstOrNull()) != null) {
@@ -194,7 +198,7 @@ public class UserUtils implements CurrentUserProvider {
         Result findUserQueryResult;
         if (internalId == null) {
             findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username).
-                    and(UserEntity.BASE_URL.eq(serverUrl))).limit(1).get();
+                                                                         and(UserEntity.BASE_URL.eq(serverUrl))).limit(1).get();
         } else {
             findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(internalId)).get();
         }
@@ -243,7 +247,7 @@ public class UserUtils implements CurrentUserProvider {
             }
 
             if ((displayName != null && user.getDisplayName() == null) || (displayName != null && user.getDisplayName()
-                    != null && !displayName.equals(user.getDisplayName()))) {
+                != null && !displayName.equals(user.getDisplayName()))) {
                 user.setDisplayName(displayName);
             }