diff --git a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt index 69ca428eb..34383387c 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt @@ -46,7 +46,7 @@ import com.nextcloud.talk.controllers.ServerSelectionController import com.nextcloud.talk.controllers.SettingsController import com.nextcloud.talk.controllers.WebViewLoginController import com.nextcloud.talk.controllers.base.providers.ActionBarProvider -import com.nextcloud.talk.data.user.model.UserNgEntity +import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ActivityMainBinding import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.json.conversations.RoomOverall @@ -60,6 +60,7 @@ 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 io.reactivex.Observer +import io.reactivex.SingleObserver import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers @@ -119,12 +120,12 @@ class MainActivity : BaseActivity(), ActionBarProvider { appPreferences.isDbRoomMigrated = true } - userManager.users.subscribe(object : Observer> { + userManager.users.subscribe(object : SingleObserver> { override fun onSubscribe(d: Disposable) { // unused atm } - override fun onNext(users: List) { + override fun onSuccess(users: List) { if (users.isNotEmpty()) { runOnUiThread { setDefaultRootController() @@ -137,11 +138,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { } override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm + Log.e(TAG, "Error loading existing users", e) } }) } else { @@ -203,12 +200,12 @@ class MainActivity : BaseActivity(), ActionBarProvider { } fun resetConversationsList() { - userManager.users.subscribe(object : Observer> { + userManager.users.subscribe(object : SingleObserver> { override fun onSubscribe(d: Disposable) { - // unused atm + TODO("Not yet implemented") } - override fun onNext(users: List) { + override fun onSuccess(users: List) { if (users.isNotEmpty()) { runOnUiThread { setDefaultRootController() @@ -217,11 +214,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { } override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm + Log.e(TAG, "Error loading existing users", e) } }) } @@ -262,7 +255,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { val user = userId.substringBeforeLast("@") val baseUrl = userId.substringAfterLast("@") - if (userManager.currentUser.blockingFirst()?.baseUrl?.endsWith(baseUrl) == true) { + if (userManager.currentUser.blockingGet()?.baseUrl?.endsWith(baseUrl) == true) { startConversation(user) } else { Snackbar.make( @@ -279,7 +272,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { private fun startConversation(userId: String) { val roomType = "1" - val currentUser = userManager.currentUser.blockingFirst() + val currentUser = userManager.currentUser.blockingGet() val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1)) val credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token) @@ -327,7 +320,7 @@ class MainActivity : BaseActivity(), ActionBarProvider { Parcels.wrap(roomOverall.ocs!!.data) ) remapChatController( - router!!, currentUser!!.id, + router!!, currentUser!!.id!!, roomOverall.ocs!!.data!!.token!!, bundle, true ) } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt b/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt index 5923aa3e7..2dc1a8f13 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/SettingsController.kt @@ -69,7 +69,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.setAppT import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.controllers.base.NewBaseController import com.nextcloud.talk.controllers.util.viewBinding -import com.nextcloud.talk.data.user.model.UserNgEntity +import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ControllerSettingsBinding import com.nextcloud.talk.jobs.AccountRemovalWorker import com.nextcloud.talk.jobs.ContactAddressBookWorker @@ -121,7 +121,7 @@ class SettingsController : NewBaseController(R.layout.controller_settings) { lateinit var currentUserProvider: CurrentUserProviderNew private var saveStateHandler: LovelySaveStateHandler? = null - private var currentUser: UserNgEntity? = null + private var currentUser: User? = null private var credentials: String? = null private var proxyTypeChangeListener: OnPreferenceValueChangedListener? = null private var proxyCredentialsChangeListener: OnPreferenceValueChangedListener? = null @@ -139,7 +139,7 @@ class SettingsController : NewBaseController(R.layout.controller_settings) { resources!!.getString(R.string.nc_settings) private fun getCurrentUser() { - currentUser = currentUserProvider.currentUser.firstOrError().blockingGet() + currentUser = currentUserProvider.currentUser.blockingGet() credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token) } @@ -187,8 +187,6 @@ class SettingsController : NewBaseController(R.layout.controller_settings) { setupPhoneBookIntegration() setupClientCertView() - - Log.i(TAG, "Current user: " + currentUser?.displayName) } private fun setupPhoneBookIntegration() { @@ -436,7 +434,7 @@ class SettingsController : NewBaseController(R.layout.controller_settings) { } private fun removeCurrentAccount() { - val otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser!!.id) + val otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser!!.id!!) val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build() WorkManager.getInstance().enqueue(accountRemovalWork) if (otherUserExists && view != null) { diff --git a/app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt b/app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt new file mode 100644 index 000000000..c89c4165c --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/data/user/UserMapper.kt @@ -0,0 +1,79 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger + * + * 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 . + */ + +package com.nextcloud.talk.data.user + +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.data.user.model.UserNgEntity + +object UserMapper { + fun toModel(entities: List?): List { + return if (entities == null) { + ArrayList() + } else { + val users = ArrayList() + for (entity in entities) { + users.add(toModel(entity)!!) + } + users + } + } + + fun toModel(entity: UserNgEntity?): User? { + return if (entity == null) { + null + } else { + User( + entity.id, + entity.userId, + entity.username, + entity.baseUrl, + entity.token, + entity.displayName, + entity.pushConfigurationState, + entity.capabilities, + entity.clientCertificate, + entity.externalSignalingServer, + entity.current, + entity.scheduledForDeletion + ) + } + } + + fun toEntity(model: User): UserNgEntity { + var userNgEntity: UserNgEntity? = null + model.id?.let { + userNgEntity = UserNgEntity(it, model.userId, model.username, model.baseUrl) + } ?: run { + userNgEntity = UserNgEntity(userId = model.userId, username = model.username, baseUrl = model.baseUrl) + } + + userNgEntity!!.token = model.token + userNgEntity!!.displayName = model.displayName + userNgEntity!!.pushConfigurationState = model.pushConfigurationState + userNgEntity!!.capabilities = model.capabilities + userNgEntity!!.clientCertificate = model.clientCertificate + userNgEntity!!.externalSignalingServer = model.externalSignalingServer + userNgEntity!!.current = model.current + userNgEntity!!.scheduledForDeletion = model.scheduledForDeletion + + return userNgEntity!! + } +} diff --git a/app/src/main/java/com/nextcloud/talk/data/user/UsersDao.kt b/app/src/main/java/com/nextcloud/talk/data/user/UsersDao.kt index 0a4b7e7bd..5f3a61d31 100644 --- a/app/src/main/java/com/nextcloud/talk/data/user/UsersDao.kt +++ b/app/src/main/java/com/nextcloud/talk/data/user/UsersDao.kt @@ -30,8 +30,8 @@ import androidx.room.Query import androidx.room.Transaction import androidx.room.Update import com.nextcloud.talk.data.user.model.UserNgEntity -import io.reactivex.Observable -import io.reactivex.Observer +import io.reactivex.Single +import io.reactivex.SingleObserver import io.reactivex.disposables.Disposable import java.lang.Boolean.FALSE import java.lang.Boolean.TRUE @@ -41,19 +41,13 @@ import java.lang.Boolean.TRUE abstract class UsersDao { // get active user @Query("SELECT * FROM User where current = 1") - abstract fun getActiveUser(): Observable + abstract fun getActiveUser(): Single @Query("SELECT * FROM User where current = 1") abstract fun getActiveUserSynchronously(): UserNgEntity? @Query("SELECT * FROM User WHERE current = 1") - abstract fun getActiveUserLiveData(): Observable - - @Query("SELECT * FROM User ORDER BY current DESC") - abstract fun getUsersLiveData(): Observable> - - @Query("SELECT * FROM User WHERE current != 1 ORDER BY current DESC") - abstract fun getUsersLiveDataWithoutActive(): Observable> + abstract fun getActiveUserLiveData(): Single @Query("DELETE FROM User WHERE id = :id") abstract fun deleteUserWithId(id: Long) @@ -69,44 +63,36 @@ abstract class UsersDao { // get all users not scheduled for deletion @Query("SELECT * FROM User where current != 0") - abstract fun getUsers(): Observable> + abstract fun getUsers(): Single> @Query("SELECT * FROM User where id = :id") - abstract fun getUserWithId(id: Long): Observable - - // TODO remove this one, duplicated - @Query("SELECT * FROM User where id = :id") - abstract fun getUserWithIdLiveData(id: Long): Observable + abstract fun getUserWithId(id: Long): Single @Query("SELECT * FROM User where id = :id AND scheduledForDeletion != 1") - abstract fun getUserWithIdNotScheduledForDeletion(id: Long): Observable + abstract fun getUserWithIdNotScheduledForDeletion(id: Long): Single @Query("SELECT * FROM User where userId = :userId") - abstract fun getUserWithUserId(userId: String): Observable + abstract fun getUserWithUserId(userId: String): Single @Query("SELECT * FROM User where userId != :userId") - abstract fun getUsersWithoutUserId(userId: Long): Observable> + abstract fun getUsersWithoutUserId(userId: Long): Single> @Query("SELECT * FROM User where current = 0") - abstract fun getUsersScheduledForDeletion(): Observable> + abstract fun getUsersScheduledForDeletion(): Single> @Query("SELECT * FROM User where scheduledForDeletion = 0") - abstract fun getUsersNotScheduledForDeletion(): Observable> + abstract fun getUsersNotScheduledForDeletion(): Single> @Query("SELECT * FROM User WHERE username = :username AND baseUrl = :server") - abstract fun getUserWithUsernameAndServer(username: String, server: String): Observable + abstract fun getUserWithUsernameAndServer(username: String, server: String): Single @Transaction open suspend fun setUserAsActiveWithId(id: Long): Boolean { val users = getUsers() var result = TRUE - users.subscribe(object : Observer> { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(users: List) { + users.subscribe(object : SingleObserver> { + override fun onSuccess(users: List) { for (user in users) { // removed from clause: && UserStatus.ACTIVE == user.status if (user.id != id) { @@ -120,14 +106,14 @@ abstract class UsersDao { } } + override fun onSubscribe(d: Disposable) { + // unused atm + } + override fun onError(e: Throwable) { Log.e(TAG, "Error setting user active", e) result = FALSE } - - override fun onComplete() { - // unused atm - } }) return result @@ -135,63 +121,29 @@ abstract class UsersDao { @Transaction open suspend fun markUserForDeletion(id: Long): Boolean { - val users = getUsers() + val users = getUsers().blockingGet() - users.subscribe(object : Observer> { - override fun onSubscribe(d: Disposable) { - // unused atm + for (user in users) { + if (user.id == id) { + user.current = FALSE + updateUser(user) } - - override fun onNext(users: List) { - for (user in users) { - if (user.id == id) { - // TODO currently we only have a boolean, no intermediate states - user.current = FALSE - updateUser(user) - break - } - } - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) + } return setAnyUserAsActive() } @Transaction open suspend fun setAnyUserAsActive(): Boolean { - val users = getUsers() + val users = getUsers().blockingGet() var result = FALSE - users.subscribe(object : Observer> { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(users: List) { - for (user in users) { - user.current = TRUE - updateUser(user) - result = TRUE - break - } - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) + for (user in users) { + user.current = TRUE + updateUser(user) + result = TRUE + break + } return result } diff --git a/app/src/main/java/com/nextcloud/talk/data/user/UsersRepository.kt b/app/src/main/java/com/nextcloud/talk/data/user/UsersRepository.kt index 8e1fa3c86..c74215b62 100644 --- a/app/src/main/java/com/nextcloud/talk/data/user/UsersRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/data/user/UsersRepository.kt @@ -22,27 +22,25 @@ package com.nextcloud.talk.data.user -import com.nextcloud.talk.data.user.model.UserNgEntity -import io.reactivex.Observable +import com.nextcloud.talk.data.user.model.User +import io.reactivex.Single @Suppress("TooManyFunctions") interface UsersRepository { - fun getActiveUserLiveData(): Observable - fun getActiveUser(): Observable - fun getActiveUserSynchronously(): UserNgEntity? - fun getUsers(): Observable> - fun getUserWithId(id: Long): Observable - fun getUserWithIdLiveData(id: Long): Observable - fun getUserWithIdNotScheduledForDeletion(id: Long): Observable - fun getUserWithUserId(userId: String): Observable - fun getUsersWithoutUserId(userId: Long): Observable> - fun getUsersLiveData(): Observable> - fun getUsersLiveDataWithoutActive(): Observable> - fun getUsersScheduledForDeletion(): Observable> - fun getUsersNotScheduledForDeletion(): Observable> - fun getUserWithUsernameAndServer(username: String, server: String): Observable - fun updateUser(user: UserNgEntity): Int - fun insertUser(user: UserNgEntity): Long + fun getActiveUserLiveData(): Single + fun getActiveUser(): Single + fun getActiveUserSynchronously(): User? + fun getUsers(): Single> + fun getUserWithId(id: Long): Single + fun getUserWithIdLiveData(id: Long): Single + fun getUserWithIdNotScheduledForDeletion(id: Long): Single + fun getUserWithUserId(userId: String): Single + fun getUsersWithoutUserId(userId: Long): Single> + fun getUsersScheduledForDeletion(): Single> + fun getUsersNotScheduledForDeletion(): Single> + fun getUserWithUsernameAndServer(username: String, server: String): Single + fun updateUser(user: User): Int + fun insertUser(user: User): Long suspend fun setUserAsActiveWithId(id: Long): Boolean fun deleteUserWithId(id: Long) suspend fun setAnyUserAsActive(): Boolean diff --git a/app/src/main/java/com/nextcloud/talk/data/user/UsersRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/data/user/UsersRepositoryImpl.kt index ca377a16b..c0966417d 100644 --- a/app/src/main/java/com/nextcloud/talk/data/user/UsersRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/data/user/UsersRepositoryImpl.kt @@ -22,73 +22,65 @@ package com.nextcloud.talk.data.user -import com.nextcloud.talk.data.user.model.UserNgEntity -import io.reactivex.Observable +import com.nextcloud.talk.data.user.model.User +import io.reactivex.Single @Suppress("TooManyFunctions") class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository { - override fun getActiveUserLiveData(): Observable { - return usersDao.getActiveUserLiveData() + override fun getActiveUserLiveData(): Single { + return usersDao.getActiveUser().map { UserMapper.toModel(it) } } - override fun getActiveUser(): Observable { - return usersDao.getActiveUser() + override fun getActiveUser(): Single { + return usersDao.getActiveUser().map { UserMapper.toModel(it) } } - override fun getActiveUserSynchronously(): UserNgEntity? { - return usersDao.getActiveUserSynchronously() + override fun getActiveUserSynchronously(): User? { + return UserMapper.toModel(usersDao.getActiveUserSynchronously()) } - override fun getUsers(): Observable> { - return usersDao.getUsers() + override fun getUsers(): Single> { + return usersDao.getUsers().map { UserMapper.toModel(it) } } - override fun getUserWithId(id: Long): Observable { - return usersDao.getUserWithId(id) + override fun getUserWithId(id: Long): Single { + return usersDao.getUserWithId(id).map { UserMapper.toModel(it) } } - override fun getUserWithIdLiveData(id: Long): Observable { - return usersDao.getUserWithIdLiveData(id).distinctUntilChanged() + override fun getUserWithIdLiveData(id: Long): Single { + return usersDao.getUserWithId(id).map { UserMapper.toModel(it) } } - override fun getUserWithIdNotScheduledForDeletion(id: Long): Observable { - return usersDao.getUserWithIdNotScheduledForDeletion(id) + override fun getUserWithIdNotScheduledForDeletion(id: Long): Single { + return usersDao.getUserWithIdNotScheduledForDeletion(id).map { UserMapper.toModel(it) } } - override fun getUserWithUserId(userId: String): Observable { - return usersDao.getUserWithUserId(userId) + override fun getUserWithUserId(userId: String): Single { + return usersDao.getUserWithUserId(userId).map { UserMapper.toModel(it) } } - override fun getUsersWithoutUserId(userId: Long): Observable> { - return usersDao.getUsersWithoutUserId(userId) + override fun getUsersWithoutUserId(userId: Long): Single> { + return usersDao.getUsersWithoutUserId(userId).map { UserMapper.toModel(it) } } - override fun getUsersLiveData(): Observable> { - return usersDao.getUsersLiveData().distinctUntilChanged() + override fun getUsersScheduledForDeletion(): Single> { + return usersDao.getUsersScheduledForDeletion().map { UserMapper.toModel(it) } } - override fun getUsersLiveDataWithoutActive(): Observable> { - return usersDao.getUsersLiveDataWithoutActive().distinctUntilChanged() + override fun getUsersNotScheduledForDeletion(): Single> { + return usersDao.getUsersNotScheduledForDeletion().map { UserMapper.toModel(it) } } - override fun getUsersScheduledForDeletion(): Observable> { - return usersDao.getUsersScheduledForDeletion() + override fun getUserWithUsernameAndServer(username: String, server: String): Single { + return usersDao.getUserWithUsernameAndServer(username, server).map { UserMapper.toModel(it) } } - override fun getUsersNotScheduledForDeletion(): Observable> { - return usersDao.getUsersNotScheduledForDeletion() + override fun updateUser(user: User): Int { + return usersDao.updateUser(UserMapper.toEntity(user)) } - override fun getUserWithUsernameAndServer(username: String, server: String): Observable { - return usersDao.getUserWithUsernameAndServer(username, server) - } - - override fun updateUser(user: UserNgEntity): Int { - return usersDao.updateUser(user) - } - - override fun insertUser(user: UserNgEntity): Long { - return usersDao.saveUser(user) + override fun insertUser(user: User): Long { + return usersDao.saveUser(UserMapper.toEntity(user)) } override suspend fun setUserAsActiveWithId(id: Long): Boolean { diff --git a/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt b/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt index b56b44347..e74792d57 100644 --- a/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt +++ b/app/src/main/java/com/nextcloud/talk/data/user/model/User.kt @@ -45,50 +45,31 @@ data class User( var current: Boolean = FALSE, var scheduledForDeletion: Boolean = FALSE, ) : Parcelable { + + fun getMaxMessageLength(): Int { + return capabilities?.spreedCapability?.config?.get("chat")?.get("max-length")?.toInt() + ?: DEFAULT_CHAT_MESSAGE_LENGTH + } + + fun getAttachmentsConfig(key: String): Any? { + return capabilities?.spreedCapability?.config?.get("attachments")?.get(key) + } + + 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) + + fun hasSpreedFeatureCapability(capabilityName: String): Boolean { + return capabilities?.spreedCapability?.features?.contains(capabilityName) ?: false + } + companion object { const val DEFAULT_CHAT_MESSAGE_LENGTH: Int = 1000 } } - -fun User.getMaxMessageLength(): Int { - return capabilities?.spreedCapability?.config?.get("chat")?.get("max-length")?.toInt() - ?: DEFAULT_CHAT_MESSAGE_LENGTH -} - -fun User.getAttachmentsConfig(key: String): Any? { - return capabilities?.spreedCapability?.config?.get("attachments")?.get(key) -} - -fun User.canUserCreateGroupConversations(): Boolean { - val canCreateValue = capabilities?.spreedCapability?.config?.get("conversations")?.get("can-create") - canCreateValue?.let { - return it.toBoolean() - } - return true -} - -fun User.getCredentials(): String = ApiUtils.getCredentials(username, token) - -fun User.hasSpreedFeatureCapability(capabilityName: String): Boolean { - return capabilities?.spreedCapability?.features?.contains(capabilityName) ?: false -} - -fun User.toUserEntity(): UserNgEntity { - var userNgEntity: UserNgEntity? = null - this.id?.let { - userNgEntity = UserNgEntity(it, userId, username, baseUrl) - } ?: run { - userNgEntity = UserNgEntity(userId = this.userId, username = this.username, baseUrl = this.baseUrl) - } - - userNgEntity!!.token = this.token - userNgEntity!!.displayName = this.displayName - userNgEntity!!.pushConfigurationState = this.pushConfigurationState - userNgEntity!!.capabilities = this.capabilities - userNgEntity!!.clientCertificate = this.clientCertificate - userNgEntity!!.externalSignalingServer = this.externalSignalingServer - userNgEntity!!.current = this.current - userNgEntity!!.scheduledForDeletion = this.scheduledForDeletion - - return userNgEntity!! -} diff --git a/app/src/main/java/com/nextcloud/talk/users/UserManager.kt b/app/src/main/java/com/nextcloud/talk/users/UserManager.kt index 8e10d47e3..625359900 100644 --- a/app/src/main/java/com/nextcloud/talk/users/UserManager.kt +++ b/app/src/main/java/com/nextcloud/talk/users/UserManager.kt @@ -24,57 +24,39 @@ package com.nextcloud.talk.users import android.text.TextUtils import com.bluelinelabs.logansquare.LoganSquare import com.nextcloud.talk.data.user.UsersRepository +import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.UserNgEntity 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.database.user.CurrentUserProviderNew -import io.reactivex.Observable -import io.reactivex.Observer -import io.reactivex.disposables.Disposable -import java.lang.Boolean.FALSE +import io.reactivex.Single import java.lang.Boolean.TRUE @Suppress("TooManyFunctions") class UserManager internal constructor(private val userRepository: UsersRepository) : CurrentUserProviderNew { - val users: Observable> + val users: Single> get() = userRepository.getUsers() - val usersScheduledForDeletion: Observable> + val usersScheduledForDeletion: Single> get() = userRepository.getUsersScheduledForDeletion() - private fun setAnyUserAndSetAsActive(): Observable { + private fun setAnyUserAndSetAsActive(): Single { val results = userRepository.getUsersNotScheduledForDeletion() - var result: UserNgEntity? = null - - results.subscribe(object : Observer> { - override fun onSubscribe(d: Disposable) { - // unused atm + return results.map { users -> + var result: User? = null + if (users.isNotEmpty()) { + val user = users[0] + user.current = true + userRepository.updateUser(user) + result = user } - - override fun onNext(users: List) { - if (users.isNotEmpty()) { - val user = users[0] - user.current = true - userRepository.updateUser(user) - result = user - } - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) - - return Observable.just(result) + result + } } - override val currentUser: Observable + override val currentUser: Single get() { return userRepository.getActiveUser() } @@ -87,176 +69,68 @@ class UserManager internal constructor(private val userRepository: UsersReposito userRepository.deleteUserWithId(internalId) } - fun getUserById(userId: String): Observable { + fun getUserById(userId: String): Single { return userRepository.getUserWithUserId(userId) } - fun getUserWithId(id: Long): Observable { + fun getUserWithId(id: Long): Single { return userRepository.getUserWithId(id) } - fun disableAllUsersWithoutId(userId: Long) { + fun disableAllUsersWithoutId(userId: Long): Single { val results = userRepository.getUsersWithoutUserId(userId) - results.subscribe(object : Observer> { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(users: List) { - if (users.isNotEmpty()) { - for (entity in users) { - entity.current = false - userRepository.updateUser(entity) - } + return results.map { users -> + var count = 0 + if (users.isNotEmpty()) { + for (entity in users) { + entity.current = false + userRepository.updateUser(entity) + count++ } } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) + count + } } - fun checkIfUserIsScheduledForDeletion(username: String, server: String): Observable { - val results = userRepository.getUserWithUsernameAndServer(username, server) - var result = FALSE - - results.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(user: UserNgEntity) { - result = user.scheduledForDeletion - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) - - return Observable.just(result) + fun checkIfUserIsScheduledForDeletion(username: String, server: String): Single { + return userRepository.getUserWithUsernameAndServer(username, server).map { it.scheduledForDeletion } } - fun getUserWithInternalId(id: Long): Observable { + fun getUserWithInternalId(id: Long): Single { return userRepository.getUserWithIdNotScheduledForDeletion(id) } - fun getIfUserWithUsernameAndServer(username: String, server: String): Observable { - val results = userRepository.getUserWithUsernameAndServer(username, server) - var result = FALSE - - results.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(users: UserNgEntity) { - result = TRUE - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) - - return Observable.just(result) + fun getIfUserWithUsernameAndServer(username: String, server: String): Single { + return userRepository.getUserWithUsernameAndServer(username, server).map { TRUE } } - suspend fun scheduleUserForDeletionWithId(id: Long): Observable { - val results = userRepository.getUserWithId(id) - var result = FALSE - - results.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(user: UserNgEntity) { - user.scheduledForDeletion = true - user.current = false - userRepository.updateUser(user) - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) - - results.subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(user: UserNgEntity) { - user.scheduledForDeletion = true - user.current = false - userRepository.updateUser(user) - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) - - setAnyUserAndSetAsActive().subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(user: UserNgEntity) { - result = TRUE - } - - override fun onError(e: Throwable) { - // unused atm - } - - override fun onComplete() { - // unused atm - } - }) - - return Observable.just(result) + fun scheduleUserForDeletionWithId(id: Long): Single { + return userRepository.getUserWithId(id).map { user -> + user.scheduledForDeletion = true + user.current = false + userRepository.updateUser(user) + }.flatMap { + setAnyUserAndSetAsActive() + }.map { TRUE } } fun createOrUpdateUser( username: String?, userAttributes: UserAttributes, - ): Observable { + ): Single { - val userObservable = if (userAttributes.id == null && username != null && userAttributes.serverUrl != null) { + val userObservable: Single = if (userAttributes.id == null && + username != null && userAttributes.serverUrl != null + ) { userRepository.getUserWithUsernameAndServer(username, userAttributes.serverUrl) - } else if (userAttributes.id != null) { - userRepository.getUserWithId(userAttributes.id) } else { - Observable.just(null) + userRepository.getUserWithId(userAttributes.id!!) } return userObservable - .map { user: UserNgEntity? -> - val userEntity = when (user) { + .map { user: User? -> + val userModel = when (user) { null -> createUser( username, userAttributes @@ -269,88 +143,31 @@ class UserManager internal constructor(private val userRepository: UsersReposito user } } - userRepository.insertUser(userEntity) + userRepository.insertUser(userModel) }.flatMap { id -> - userRepository.getUserWithIdLiveData(id) + userRepository.getUserWithId(id) } } - fun getUserWithUsernameAndServer(username: String, server: String): Observable { + fun getUserWithUsernameAndServer(username: String, server: String): Single { return userRepository.getUserWithUsernameAndServer(username, server) } - private fun updateUserData(user: UserNgEntity, userAttributes: UserAttributes) { - updateUserIdIfNeeded(userAttributes, user) - updateTokenIfNeeded(userAttributes, user) - updateDisplayNameIfNeeded(userAttributes, user) - updatePushConfigurationStateIfNeeded(userAttributes, user) - updateCapabilitiesIfNeeded(userAttributes, user) - updateCertificateAliasIfNeeded(userAttributes, user) - updateExternalSignalingServerIfNeeded(userAttributes, user) - updateCurrentUserStatusIfNeeded(userAttributes, user) + private fun updateUserData(user: User, userAttributes: UserAttributes) { + user.userId = userAttributes.userId + user.token = userAttributes.token + user.displayName = userAttributes.displayName + user.pushConfigurationState = LoganSquare + .parse(userAttributes.pushConfigurationState, PushConfigurationState::class.java) + user.capabilities = LoganSquare.parse(userAttributes.capabilities, Capabilities::class.java) + user.clientCertificate = userAttributes.certificateAlias + user.externalSignalingServer = LoganSquare + .parse(userAttributes.externalSignalingServer, ExternalSignalingServer::class.java) + user.current = userAttributes.currentUser == true } - private fun updateCurrentUserStatusIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (userAttributes.currentUser != null) { - user.current = userAttributes.currentUser - } - } - - private fun updateExternalSignalingServerIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (userAttributes.externalSignalingServer != null) { - val newExternalSignalingServer = LoganSquare - .parse(userAttributes.externalSignalingServer, ExternalSignalingServer::class.java) - if (newExternalSignalingServer != user.externalSignalingServer) { - user.externalSignalingServer = newExternalSignalingServer - } - } - } - - private fun updateCertificateAliasIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (userAttributes.certificateAlias != null && userAttributes.certificateAlias != user.clientCertificate) { - user.clientCertificate = userAttributes.certificateAlias - } - } - - private fun updateCapabilitiesIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (userAttributes.capabilities != null) { - val newCapabilities = LoganSquare.parse(userAttributes.capabilities, Capabilities::class.java) - if (newCapabilities != user.capabilities) { - user.capabilities = newCapabilities - } - } - } - - private fun updatePushConfigurationStateIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (userAttributes.pushConfigurationState != null) { - val newPushConfigurationState = LoganSquare - .parse(userAttributes.pushConfigurationState, PushConfigurationState::class.java) - if (newPushConfigurationState != user.pushConfigurationState) { - user.pushConfigurationState = newPushConfigurationState - } - } - } - - private fun updateDisplayNameIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (validDisplayName(userAttributes.displayName, user)) { - user.displayName = userAttributes.displayName - } - } - - private fun updateTokenIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (userAttributes.token != null && userAttributes.token != user.token) { - user.token = userAttributes.token - } - } - - private fun updateUserIdIfNeeded(userAttributes: UserAttributes, user: UserNgEntity) { - if (userAttributes.userId != null && (user.userId == null || user.userId != userAttributes.userId)) { - user.userId = userAttributes.userId - } - } - - private fun createUser(username: String?, userAttributes: UserAttributes): UserNgEntity { - val user = UserNgEntity() + private fun createUser(username: String?, userAttributes: UserAttributes): User { + val user = User() user.baseUrl = userAttributes.serverUrl user.username = username user.token = userAttributes.token diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java index 8b0e88adb..6ad3e3e47 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java @@ -28,6 +28,7 @@ import android.util.Log; import com.nextcloud.talk.BuildConfig; import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; +import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.data.user.model.UserNgEntity; import com.nextcloud.talk.models.RetrofitBucket; import com.nextcloud.talk.models.database.CapabilitiesUtil; @@ -124,7 +125,7 @@ public class ApiUtils { return getConversationApiVersion(capabilities, versions); } - public static int getConversationApiVersion(UserNgEntity user, int[] versions) throws NoSupportedApiException { + public static int getConversationApiVersion(User user, int[] versions) throws NoSupportedApiException { boolean hasApiV4 = false; for (int version : versions) { hasApiV4 |= version == APIv4; diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index 70392597b..f704cb523 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -79,6 +79,7 @@ import com.facebook.widget.text.span.BetterImageSpan; import com.google.android.material.chip.ChipDrawable; import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; +import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.data.user.model.UserNgEntity; import com.nextcloud.talk.events.UserMentionClickEvent; import com.nextcloud.talk.models.database.UserEntity; @@ -599,7 +600,7 @@ public class DisplayUtils { avatarImageView.setController(draweeController); } - public static void loadAvatarImage(UserNgEntity user, SimpleDraweeView avatarImageView, boolean deleteCache) { + public static void loadAvatarImage(User user, SimpleDraweeView avatarImageView, boolean deleteCache) { String avatarId; if (!TextUtils.isEmpty(user.getUserId())) { avatarId = user.getUserId(); diff --git a/app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesNgUtil.java b/app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesNgUtil.java index 010bf98e0..35fb5ea33 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesNgUtil.java +++ b/app/src/main/java/com/nextcloud/talk/utils/database/user/CapabilitiesNgUtil.java @@ -21,7 +21,7 @@ */ package com.nextcloud.talk.utils.database.user; -import com.nextcloud.talk.data.user.model.UserNgEntity; +import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.models.json.capabilities.Capabilities; import java.util.HashMap; @@ -32,7 +32,7 @@ import androidx.annotation.Nullable; public abstract class CapabilitiesNgUtil { private static final String TAG = CapabilitiesNgUtil.class.getSimpleName(); - public static boolean hasNotificationsCapability(@Nullable UserNgEntity user, String capabilityName) { + public static boolean hasNotificationsCapability(@Nullable User user, String capabilityName) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities.getNotificationsCapability() != null && @@ -43,7 +43,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean hasExternalCapability(@Nullable UserNgEntity user, String capabilityName) { + public static boolean hasExternalCapability(@Nullable User user, String capabilityName) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities.getExternalCapability() != null && @@ -54,21 +54,21 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean isServerEOL(@Nullable UserNgEntity user) { + 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 UserNgEntity user) { + 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 UserNgEntity user) { + public static boolean canSetChatReadMarker(@Nullable User user) { return hasSpreedFeatureCapability(user, "chat-read-marker"); } - public static boolean hasSpreedFeatureCapability(@Nullable UserNgEntity user, String capabilityName) { + 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 && @@ -79,7 +79,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static Integer getMessageMaxLength(@Nullable UserNgEntity user) { + public static Integer getMessageMaxLength(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities != null && @@ -103,7 +103,7 @@ public abstract class CapabilitiesNgUtil { return 1000; } - public static boolean isPhoneBookIntegrationAvailable(@Nullable UserNgEntity user) { + public static boolean isPhoneBookIntegrationAvailable(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); return capabilities != null && @@ -114,7 +114,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean isReadStatusAvailable(@Nullable UserNgEntity user) { + public static boolean isReadStatusAvailable(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities != null && @@ -128,7 +128,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean isReadStatusPrivate(@Nullable UserNgEntity user) { + public static boolean isReadStatusPrivate(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities != null && @@ -144,7 +144,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean isUserStatusAvailable(@Nullable UserNgEntity user) { + public static boolean isUserStatusAvailable(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities.getUserStatusCapability() != null && @@ -156,7 +156,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static String getAttachmentFolder(@Nullable UserNgEntity user) { + public static String getAttachmentFolder(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities != null && @@ -172,7 +172,7 @@ public abstract class CapabilitiesNgUtil { return "/Talk"; } - public static String getServerName(@Nullable UserNgEntity user) { + public static String getServerName(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities != null && capabilities.getThemingCapability() != null) { @@ -183,7 +183,7 @@ public abstract class CapabilitiesNgUtil { } // TODO later avatar can also be checked via user fields, for now it is in Talk capability - public static boolean isAvatarEndpointAvailable(@Nullable UserNgEntity user) { + public static boolean isAvatarEndpointAvailable(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); return (capabilities != null && @@ -194,7 +194,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean canEditScopes(@Nullable UserNgEntity user) { + public static boolean canEditScopes(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); return (capabilities != null && @@ -205,7 +205,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean isAbleToCall(@Nullable UserNgEntity user) { + public static boolean isAbleToCall(@Nullable User user) { if (user != null && user.getCapabilities() != null) { Capabilities capabilities = user.getCapabilities(); if (capabilities != null && @@ -224,7 +224,7 @@ public abstract class CapabilitiesNgUtil { return false; } - public static boolean isUnifiedSearchAvailable(@Nullable final UserNgEntity user) { + public static boolean isUnifiedSearchAvailable(@Nullable final User user) { return hasSpreedFeatureCapability(user, "unified-search"); } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderNew.kt b/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderNew.kt index ec40c6db8..0d138648f 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderNew.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderNew.kt @@ -20,9 +20,9 @@ */ package com.nextcloud.talk.utils.database.user -import com.nextcloud.talk.data.user.model.UserNgEntity -import io.reactivex.Observable +import com.nextcloud.talk.data.user.model.User +import io.reactivex.Single interface CurrentUserProviderNew { - val currentUser: Observable + val currentUser: Single }