move everything to flows

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
This commit is contained in:
Andy Scherzinger 2022-06-20 18:33:19 +02:00
parent 730aeb2944
commit 8c27b54377
No known key found for this signature in database
GPG Key ID: 6CADC7E3523C308B
10 changed files with 306 additions and 209 deletions

View File

@ -66,9 +66,6 @@
<MarkdownNavigatorCodeStyleSettings> <MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="120" /> <option name="RIGHT_MARGIN" value="120" />
</MarkdownNavigatorCodeStyleSettings> </MarkdownNavigatorCodeStyleSettings>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="JAVA"> <codeStyleSettings language="JAVA">
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" /> <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="ALIGN_MULTILINE_METHOD_BRACKETS" value="true" /> <option name="ALIGN_MULTILINE_METHOD_BRACKETS" value="true" />

View File

@ -209,6 +209,7 @@ dependencies {
implementation "androidx.exifinterface:exifinterface:1.3.3" implementation "androidx.exifinterface:exifinterface:1.3.3"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
implementation 'androidx.biometric:biometric:1.1.0' implementation 'androidx.biometric:biometric:1.1.0'

View File

@ -117,13 +117,15 @@ class MainActivity : BaseActivity(), ActionBarProvider {
} else if (!router!!.hasRootController()) { } else if (!router!!.hasRootController()) {
if (hasDb) { if (hasDb) {
GlobalScope.launch { GlobalScope.launch {
if (usersRepository.getUsers().isNotEmpty()) { usersRepository.getUsers().collect {
runOnUiThread { if (it.isNotEmpty()) {
setDefaultRootController() runOnUiThread {
} setDefaultRootController()
} else { }
runOnUiThread { } else {
launchLoginScreen() runOnUiThread {
launchLoginScreen()
}
} }
} }
} }
@ -186,8 +188,14 @@ class MainActivity : BaseActivity(), ActionBarProvider {
} }
fun resetConversationsList() { fun resetConversationsList() {
if (usersRepository.getUsers().isNotEmpty()) { GlobalScope.launch {
setDefaultRootController() usersRepository.getUsers().collect {
if (it.isNotEmpty()) {
runOnUiThread {
setDefaultRootController()
}
}
}
} }
} }
@ -226,14 +234,22 @@ class MainActivity : BaseActivity(), ActionBarProvider {
"vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat" -> { "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat" -> {
val user = userId.substringBeforeLast("@") val user = userId.substringBeforeLast("@")
val baseUrl = userId.substringAfterLast("@") val baseUrl = userId.substringAfterLast("@")
if (usersRepository.getActiveUser()?.baseUrl?.endsWith(baseUrl) == true) { GlobalScope.launch {
startConversation(user) usersRepository.getActiveUser().collect {
} else { if (it?.baseUrl?.endsWith(baseUrl) == true) {
Snackbar.make( runOnUiThread {
binding.controllerContainer, startConversation(user)
R.string.nc_phone_book_integration_account_not_found, }
Snackbar.LENGTH_LONG } else {
).show() runOnUiThread {
Snackbar.make(
binding.controllerContainer,
R.string.nc_phone_book_integration_account_not_found,
Snackbar.LENGTH_LONG
).show()
}
}
}
} }
} }
} }
@ -242,38 +258,19 @@ class MainActivity : BaseActivity(), ActionBarProvider {
private fun startConversation(userId: String) { private fun startConversation(userId: String) {
val roomType = "1" val roomType = "1"
val currentUser = usersRepository.getActiveUser() ?: return
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1)) GlobalScope.launch {
val credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token) usersRepository.getActiveUser().collect { currentUser ->
val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( if (currentUser != null) {
apiVersion, currentUser.baseUrl, roomType, val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1))
null, userId, null val credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token)
) val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
ncApi.createRoom( apiVersion, currentUser.baseUrl, roomType,
credentials, null, userId, null
retrofitBucket.url, retrofitBucket.queryMap )
) ncApi.createRoom(
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(roomOverall: RoomOverall) {
val bundle = Bundle()
bundle.putParcelable(KEY_USER_ENTITY, currentUser)
bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs!!.data!!.token)
bundle.putString(KEY_ROOM_ID, roomOverall.ocs!!.data!!.roomId)
// FIXME once APIv2 or later is used only, the createRoom already returns all the data
ncApi.getRoom(
credentials, credentials,
ApiUtils.getUrlForRoom( retrofitBucket.url, retrofitBucket.queryMap
apiVersion,
currentUser.baseUrl,
roomOverall.ocs!!.data!!.token
)
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -281,33 +278,61 @@ class MainActivity : BaseActivity(), ActionBarProvider {
override fun onSubscribe(d: Disposable) { override fun onSubscribe(d: Disposable) {
// unused atm // unused atm
} }
override fun onNext(roomOverall: RoomOverall) { override fun onNext(roomOverall: RoomOverall) {
bundle.putParcelable( val bundle = Bundle()
KEY_ACTIVE_CONVERSATION, bundle.putParcelable(KEY_USER_ENTITY, currentUser)
Parcels.wrap(roomOverall.ocs!!.data) bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs!!.data!!.token)
) bundle.putString(KEY_ROOM_ID, roomOverall.ocs!!.data!!.roomId)
remapChatController(
router!!, currentUser.id, // FIXME once APIv2 or later is used only, the createRoom already returns all the data
roomOverall.ocs!!.data!!.token!!, bundle, true ncApi.getRoom(
credentials,
ApiUtils.getUrlForRoom(
apiVersion,
currentUser.baseUrl,
roomOverall.ocs!!.data!!.token
)
) )
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(roomOverall: RoomOverall) {
bundle.putParcelable(
KEY_ACTIVE_CONVERSATION,
Parcels.wrap(roomOverall.ocs!!.data)
)
remapChatController(
router!!, currentUser.id,
roomOverall.ocs!!.data!!.token!!, bundle, true
)
}
override fun onError(e: Throwable) {
// unused atm
}
override fun onComplete() {
// unused atm
}
})
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
// unused atm // unused atm
} }
override fun onComplete() { override fun onComplete() {
// unused atm // unused atm
} }
}) })
} }
}
override fun onError(e: Throwable) { }
// unused atm
}
override fun onComplete() {
// unused atm
}
})
} }
@RequiresApi(api = Build.VERSION_CODES.M) @RequiresApi(api = Build.VERSION_CODES.M)
@ -359,6 +384,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
} }
companion object { companion object {
private val TAG = "MainActivity" private const val TAG = "MainActivity"
} }
} }

View File

@ -53,6 +53,7 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.lifecycle.lifecycleScope
import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager import androidx.work.WorkManager
import autodagger.AutoInjector import autodagger.AutoInjector
@ -63,6 +64,7 @@ import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.nextcloud.talk.BuildConfig import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MainActivity
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.setAppTheme import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.setAppTheme
@ -89,6 +91,7 @@ import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri
import com.nextcloud.talk.utils.SecurityUtils import com.nextcloud.talk.utils.SecurityUtils
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ARE_CALL_SOUNDS import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ARE_CALL_SOUNDS
import com.nextcloud.talk.utils.database.user.CapabilitiesNgUtil import com.nextcloud.talk.utils.database.user.CapabilitiesNgUtil
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
import com.nextcloud.talk.utils.database.user.UserUtils import com.nextcloud.talk.utils.database.user.UserUtils
import com.nextcloud.talk.utils.preferences.MagicUserInputModule import com.nextcloud.talk.utils.preferences.MagicUserInputModule
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
@ -98,6 +101,9 @@ import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody import okhttp3.RequestBody
@ -120,6 +126,9 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
@Inject @Inject
lateinit var userRepository: UsersRepository lateinit var userRepository: UsersRepository
@Inject
lateinit var currentUserProvider: CurrentUserProviderNew
private var saveStateHandler: LovelySaveStateHandler? = null private var saveStateHandler: LovelySaveStateHandler? = null
private var currentUser: UserNgEntity? = null private var currentUser: UserNgEntity? = null
private var credentials: String? = null private var credentials: String? = null
@ -134,13 +143,19 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
private var profileQueryDisposable: Disposable? = null private var profileQueryDisposable: Disposable? = null
private var dbQueryDisposable: Disposable? = null private var dbQueryDisposable: Disposable? = null
val scope = MainScope()
override val title: String override val title: String
get() = get() =
resources!!.getString(R.string.nc_settings) resources!!.getString(R.string.nc_settings)
private fun getCurrentUser() { private fun getCurrentUser() {
currentUser = userRepository.getActiveUser() (activity as MainActivity).lifecycleScope.launchWhenCreated {
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token) currentUserProvider.currentUser.collect {
currentUser = it
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
}
}
} }
override fun onViewBound(view: View) { override fun onViewBound(view: View) {
@ -189,10 +204,18 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
} }
private fun setupPhoneBookIntegration() { private fun setupPhoneBookIntegration() {
if (CapabilitiesNgUtil.isPhoneBookIntegrationAvailable(userRepository.getActiveUser())) { scope.launch {
binding.settingsPhoneBookIntegration.visibility = View.VISIBLE userRepository.getActiveUser().collect {
} else { if (CapabilitiesNgUtil.isPhoneBookIntegrationAvailable(it)) {
binding.settingsPhoneBookIntegration.visibility = View.GONE activity!!.runOnUiThread {
binding.settingsPhoneBookIntegration.visibility = View.VISIBLE
}
} else {
activity!!.runOnUiThread {
binding.settingsPhoneBookIntegration.visibility = View.GONE
}
}
}
} }
} }
@ -730,6 +753,8 @@ class SettingsController : NewBaseController(R.layout.controller_settings) {
appPreferences?.unregisterReadPrivacyChangeListener(readPrivacyChangeListener) appPreferences?.unregisterReadPrivacyChangeListener(readPrivacyChangeListener)
appPreferences?.unregisterPhoneBookIntegrationChangeListener(phoneBookIntegrationChangeListener) appPreferences?.unregisterPhoneBookIntegrationChangeListener(phoneBookIntegrationChangeListener)
scope.cancel()
super.onDestroy() super.onDestroy()
} }

View File

@ -22,7 +22,6 @@
package com.nextcloud.talk.data.user package com.nextcloud.talk.data.user
import androidx.lifecycle.LiveData
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
@ -30,6 +29,8 @@ import androidx.room.Query
import androidx.room.Transaction import androidx.room.Transaction
import androidx.room.Update import androidx.room.Update
import com.nextcloud.talk.data.user.model.UserNgEntity import com.nextcloud.talk.data.user.model.UserNgEntity
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import java.lang.Boolean.FALSE import java.lang.Boolean.FALSE
import java.lang.Boolean.TRUE import java.lang.Boolean.TRUE
@ -38,16 +39,16 @@ import java.lang.Boolean.TRUE
abstract class UsersDao { abstract class UsersDao {
// get active user // get active user
@Query("SELECT * FROM User where current = 1") @Query("SELECT * FROM User where current = 1")
abstract fun getActiveUser(): UserNgEntity? abstract fun getActiveUser(): Flow<UserNgEntity?>
@Query("SELECT * FROM User WHERE current = 1") @Query("SELECT * FROM User WHERE current = 1")
abstract fun getActiveUserLiveData(): LiveData<UserNgEntity?> abstract fun getActiveUserLiveData(): Flow<UserNgEntity?>
@Query("SELECT * FROM User ORDER BY current DESC") @Query("SELECT * FROM User ORDER BY current DESC")
abstract fun getUsersLiveData(): LiveData<List<UserNgEntity>> abstract fun getUsersLiveData(): Flow<List<UserNgEntity>>
@Query("SELECT * FROM User WHERE current != 1 ORDER BY current DESC") @Query("SELECT * FROM User WHERE current != 1 ORDER BY current DESC")
abstract fun getUsersLiveDataWithoutActive(): LiveData<List<UserNgEntity>> abstract fun getUsersLiveDataWithoutActive(): Flow<List<UserNgEntity>>
@Query("DELETE FROM User WHERE id = :id") @Query("DELETE FROM User WHERE id = :id")
abstract suspend fun deleteUserWithId(id: Long) abstract suspend fun deleteUserWithId(id: Long)
@ -56,66 +57,70 @@ abstract class UsersDao {
abstract suspend fun updateUser(user: UserNgEntity): Int abstract suspend fun updateUser(user: UserNgEntity): Int
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun saveUser(user: UserNgEntity): Long abstract suspend fun saveUser(user: UserNgEntity): Long
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun saveUsers(vararg users: UserNgEntity): List<Long> abstract suspend fun saveUsers(vararg users: UserNgEntity): List<Long>
// get all users not scheduled for deletion // get all users not scheduled for deletion
@Query("SELECT * FROM User where current != 0") @Query("SELECT * FROM User where current != 0")
abstract fun getUsers(): List<UserNgEntity> abstract fun getUsers(): Flow<List<UserNgEntity>>
@Query("SELECT * FROM User where id = :id") @Query("SELECT * FROM User where id = :id")
abstract fun getUserWithId(id: Long): UserNgEntity? abstract fun getUserWithId(id: Long): Flow<UserNgEntity?>
@Query("SELECT * FROM User where id = :id") @Query("SELECT * FROM User where id = :id")
abstract fun getUserWithIdLiveData(id: Long): LiveData<UserNgEntity?> abstract fun getUserWithIdLiveData(id: Long): Flow<UserNgEntity?>
@Query("SELECT * FROM User where id = :id AND scheduledForDeletion != 1") @Query("SELECT * FROM User where id = :id AND scheduledForDeletion != 1")
abstract fun getUserWithIdNotScheduledForDeletion(id: Long): UserNgEntity? abstract fun getUserWithIdNotScheduledForDeletion(id: Long): Flow<UserNgEntity?>
@Query("SELECT * FROM User where userId = :userId") @Query("SELECT * FROM User where userId = :userId")
abstract fun getUserWithUserId(userId: String): UserNgEntity? abstract fun getUserWithUserId(userId: String): Flow<UserNgEntity?>
@Query("SELECT * FROM User where userId != :userId") @Query("SELECT * FROM User where userId != :userId")
abstract fun getUsersWithoutUserId(userId: Long): List<UserNgEntity> abstract fun getUsersWithoutUserId(userId: Long): Flow<List<UserNgEntity>>
@Query("SELECT * FROM User where current = 0") @Query("SELECT * FROM User where current = 0")
abstract fun getUsersScheduledForDeletion(): List<UserNgEntity> abstract fun getUsersScheduledForDeletion(): Flow<List<UserNgEntity>>
@Query("SELECT * FROM User where scheduledForDeletion = 0") @Query("SELECT * FROM User where scheduledForDeletion = 0")
abstract fun getUsersNotScheduledForDeletion(): List<UserNgEntity> abstract fun getUsersNotScheduledForDeletion(): Flow<List<UserNgEntity>>
@Query("SELECT * FROM User WHERE username = :username AND baseUrl = :server") @Query("SELECT * FROM User WHERE username = :username AND baseUrl = :server")
abstract suspend fun getUserWithUsernameAndServer(username: String, server: String): UserNgEntity? abstract fun getUserWithUsernameAndServer(username: String, server: String): Flow<UserNgEntity?>
@Transaction @Transaction
open suspend fun setUserAsActiveWithId(id: Long): Boolean { open suspend fun setUserAsActiveWithId(id: Long): Flow<Boolean> {
val users = getUsers() val users = getUsers()
for (user in users) { users.collect {
// removed from clause: && UserStatus.ACTIVE == user.status for (user in it) {
if (user.id != id) { // removed from clause: && UserStatus.ACTIVE == user.status
user.current = TRUE if (user.id != id) {
updateUser(user) user.current = TRUE
} // removed from clause: && UserStatus.ACTIVE != user.status updateUser(user)
else if (user.id == id) { } // removed from clause: && UserStatus.ACTIVE != user.status
user.current = TRUE else if (user.id == id) {
updateUser(user) user.current = TRUE
updateUser(user)
}
} }
} }
return true return flowOf(TRUE)
} }
@Transaction @Transaction
open suspend fun markUserForDeletion(id: Long): Boolean { open suspend fun markUserForDeletion(id: Long): Flow<Boolean> {
val users = getUsers() val users = getUsers()
for (user in users) { users.collect {
if (user.id == id) { for (user in it) {
// TODO currently we only have a boolean, no intermediate states if (user.id == id) {
user.current = FALSE // TODO currently we only have a boolean, no intermediate states
updateUser(user) user.current = FALSE
break updateUser(user)
break
}
} }
} }
@ -123,14 +128,18 @@ abstract class UsersDao {
} }
@Transaction @Transaction
open suspend fun setAnyUserAsActive(): Boolean { open suspend fun setAnyUserAsActive(): Flow<Boolean> {
val users = getUsers() val users = getUsers()
for (user in users) { var result = FALSE
user.current = TRUE users.collect {
updateUser(user) for (user in it) {
return true user.current = TRUE
updateUser(user)
result = true
break
}
} }
return false return flowOf(result)
} }
} }

View File

@ -22,29 +22,28 @@
package com.nextcloud.talk.data.user package com.nextcloud.talk.data.user
import androidx.lifecycle.LiveData
import com.nextcloud.talk.data.user.model.UserNgEntity import com.nextcloud.talk.data.user.model.UserNgEntity
import com.nextcloud.talk.data.user.model.User import kotlinx.coroutines.flow.Flow
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
interface UsersRepository { interface UsersRepository {
fun getActiveUserLiveData(): LiveData<UserNgEntity?> fun getActiveUserLiveData(): Flow<UserNgEntity?>
fun getActiveUser(): UserNgEntity? fun getActiveUser(): Flow<UserNgEntity?>
fun getUsers(): List<UserNgEntity> fun getUsers(): Flow<List<UserNgEntity>>
fun getUserWithId(id: Long): UserNgEntity? fun getUserWithId(id: Long): Flow<UserNgEntity?>
fun getUserWithIdLiveData(id: Long): LiveData<UserNgEntity?> fun getUserWithIdLiveData(id: Long): Flow<UserNgEntity?>
fun getUserWithIdNotScheduledForDeletion(id: Long): UserNgEntity? fun getUserWithIdNotScheduledForDeletion(id: Long): Flow<UserNgEntity?>
fun getUserWithUserId(userId: String): UserNgEntity? fun getUserWithUserId(userId: String): Flow<UserNgEntity?>
fun getUsersWithoutUserId(userId: Long): List<UserNgEntity> fun getUsersWithoutUserId(userId: Long): Flow<List<UserNgEntity>>
fun getUsersLiveData(): LiveData<List<User>> fun getUsersLiveData(): Flow<List<UserNgEntity>>
fun getUsersLiveDataWithoutActive(): LiveData<List<User>> fun getUsersLiveDataWithoutActive(): Flow<List<UserNgEntity>>
fun getUsersScheduledForDeletion(): List<UserNgEntity> fun getUsersScheduledForDeletion(): Flow<List<UserNgEntity>>
fun getUsersNotScheduledForDeletion(): List<UserNgEntity> fun getUsersNotScheduledForDeletion(): Flow<List<UserNgEntity>>
suspend fun getUserWithUsernameAndServer(username: String, server: String): UserNgEntity? fun getUserWithUsernameAndServer(username: String, server: String): Flow<UserNgEntity?>
suspend fun updateUser(user: UserNgEntity): Int suspend fun updateUser(user: UserNgEntity): Int
suspend fun insertUser(user: UserNgEntity): Long suspend fun insertUser(user: UserNgEntity): Long
suspend fun setUserAsActiveWithId(id: Long): Boolean suspend fun setUserAsActiveWithId(id: Long): Flow<Boolean>
suspend fun deleteUserWithId(id: Long) suspend fun deleteUserWithId(id: Long)
suspend fun setAnyUserAsActive(): Boolean suspend fun setAnyUserAsActive(): Flow<Boolean>
suspend fun markUserForDeletion(id: Long): Boolean suspend fun markUserForDeletion(id: Long): Flow<Boolean>
} }

View File

@ -22,75 +22,61 @@
package com.nextcloud.talk.data.user package com.nextcloud.talk.data.user
import androidx.lifecycle.LiveData
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.map
import com.nextcloud.talk.data.user.model.UserNgEntity import com.nextcloud.talk.data.user.model.UserNgEntity
import com.nextcloud.talk.data.user.model.User import kotlinx.coroutines.flow.Flow
import com.nextcloud.talk.data.user.model.toUser import kotlinx.coroutines.flow.distinctUntilChanged
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository { class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
override fun getActiveUserLiveData(): LiveData<UserNgEntity?> { override fun getActiveUserLiveData(): Flow<UserNgEntity?> {
return usersDao.getActiveUserLiveData().distinctUntilChanged() return usersDao.getActiveUserLiveData().distinctUntilChanged()
} }
override fun getActiveUser(): UserNgEntity? { override fun getActiveUser(): Flow<UserNgEntity?> {
return usersDao.getActiveUser() return usersDao.getActiveUser()
} }
override fun getUsers(): List<UserNgEntity> { override fun getUsers(): Flow<List<UserNgEntity>> {
return usersDao.getUsers() return usersDao.getUsers()
} }
override fun getUserWithId(id: Long): UserNgEntity? { override fun getUserWithId(id: Long): Flow<UserNgEntity?> {
return usersDao.getUserWithId(id) return usersDao.getUserWithId(id)
} }
override fun getUserWithIdLiveData(id: Long): LiveData<UserNgEntity?> { override fun getUserWithIdLiveData(id: Long): Flow<UserNgEntity?> {
return usersDao.getUserWithIdLiveData(id).distinctUntilChanged() return usersDao.getUserWithIdLiveData(id).distinctUntilChanged()
} }
override fun getUserWithIdNotScheduledForDeletion(id: Long): UserNgEntity? { override fun getUserWithIdNotScheduledForDeletion(id: Long): Flow<UserNgEntity?> {
return usersDao.getUserWithIdNotScheduledForDeletion(id) return usersDao.getUserWithIdNotScheduledForDeletion(id)
} }
override fun getUserWithUserId(userId: String): UserNgEntity? { override fun getUserWithUserId(userId: String): Flow<UserNgEntity?> {
return usersDao.getUserWithUserId(userId) return usersDao.getUserWithUserId(userId)
} }
override fun getUsersWithoutUserId(userId: Long): List<UserNgEntity> { override fun getUsersWithoutUserId(userId: Long): Flow<List<UserNgEntity>> {
return usersDao.getUsersWithoutUserId(userId) return usersDao.getUsersWithoutUserId(userId)
} }
override fun getUsersLiveData(): LiveData<List<User>> { override fun getUsersLiveData(): Flow<List<UserNgEntity>> {
return usersDao.getUsersLiveData().distinctUntilChanged().map { usersList -> return usersDao.getUsersLiveData().distinctUntilChanged()
usersList.map {
it.toUser()
}
}
} }
override fun getUsersLiveDataWithoutActive(): LiveData<List<User>> { override fun getUsersLiveDataWithoutActive(): Flow<List<UserNgEntity>> {
return usersDao.getUsersLiveDataWithoutActive().distinctUntilChanged().map { usersList -> return usersDao.getUsersLiveDataWithoutActive().distinctUntilChanged()
usersList.map {
it.toUser()
}
}
} }
override fun getUsersScheduledForDeletion(): List<UserNgEntity> { override fun getUsersScheduledForDeletion(): Flow<List<UserNgEntity>> {
return usersDao.getUsersScheduledForDeletion() return usersDao.getUsersScheduledForDeletion()
} }
override fun getUsersNotScheduledForDeletion(): List<UserNgEntity> { override fun getUsersNotScheduledForDeletion(): Flow<List<UserNgEntity>> {
return usersDao.getUsersNotScheduledForDeletion() return usersDao.getUsersNotScheduledForDeletion()
} }
override suspend fun getUserWithUsernameAndServer( override fun getUserWithUsernameAndServer(username: String, server: String): Flow<UserNgEntity?> {
username: String,
server: String
): UserNgEntity? {
return usersDao.getUserWithUsernameAndServer(username, server) return usersDao.getUserWithUsernameAndServer(username, server)
} }
@ -102,7 +88,7 @@ class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
return usersDao.saveUser(user) return usersDao.saveUser(user)
} }
override suspend fun setUserAsActiveWithId(id: Long): Boolean { override suspend fun setUserAsActiveWithId(id: Long): Flow<Boolean> {
return usersDao.setUserAsActiveWithId(id) return usersDao.setUserAsActiveWithId(id)
} }
@ -110,11 +96,11 @@ class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
usersDao.deleteUserWithId(id) usersDao.deleteUserWithId(id)
} }
override suspend fun setAnyUserAsActive(): Boolean { override suspend fun setAnyUserAsActive(): Flow<Boolean> {
return usersDao.setAnyUserAsActive() return usersDao.setAnyUserAsActive()
} }
override suspend fun markUserForDeletion(id: Long): Boolean { override suspend fun markUserForDeletion(id: Long): Flow<Boolean> {
return usersDao.markUserForDeletion(id) return usersDao.markUserForDeletion(id)
} }
} }

View File

@ -22,7 +22,6 @@
package com.nextcloud.talk.users package com.nextcloud.talk.users
import android.text.TextUtils import android.text.TextUtils
import androidx.lifecycle.LiveData
import com.bluelinelabs.logansquare.LoganSquare import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.data.user.UsersRepository import com.nextcloud.talk.data.user.UsersRepository
import com.nextcloud.talk.data.user.model.UserNgEntity import com.nextcloud.talk.data.user.model.UserNgEntity
@ -30,35 +29,54 @@ import com.nextcloud.talk.models.ExternalSignalingServer
import com.nextcloud.talk.models.json.capabilities.Capabilities import com.nextcloud.talk.models.json.capabilities.Capabilities
import com.nextcloud.talk.models.json.push.PushConfigurationState import com.nextcloud.talk.models.json.push.PushConfigurationState
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import java.lang.Boolean.FALSE
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
class UserManager internal constructor(private val userRepository: UsersRepository) : CurrentUserProviderNew { class UserManager internal constructor(private val userRepository: UsersRepository) : CurrentUserProviderNew {
fun anyUserExists(): Boolean { suspend fun anyUserExists(): Boolean {
return userRepository.getUsers().isNotEmpty() var result = FALSE
userRepository.getUsers().collect {
result = it.isNotEmpty()
}
return result
} }
fun hasMultipleUsers(): Boolean { suspend fun hasMultipleUsers(): Flow<Boolean> {
return userRepository.getUsers().size > 1 var result = FALSE
userRepository.getUsers().collect {
result = it.size > 1
}
return flowOf(result)
} }
val users: List<UserNgEntity> val users: Flow<List<UserNgEntity>>
get() = userRepository.getUsers() get() = userRepository.getUsers()
val usersScheduledForDeletion: List<UserNgEntity> val usersScheduledForDeletion: Flow<List<UserNgEntity>>
get() = userRepository.getUsersScheduledForDeletion() get() = userRepository.getUsersScheduledForDeletion()
suspend fun setAnyUserAndSetAsActive(): UserNgEntity? { private suspend fun setAnyUserAndSetAsActive(): Flow<UserNgEntity?> {
val results = userRepository.getUsersNotScheduledForDeletion() val results = userRepository.getUsersNotScheduledForDeletion()
if (results.isNotEmpty()) {
val user = results[0] var result: UserNgEntity? = null
user.current = true
userRepository.updateUser(user) results.collect {
return user if (it.isNotEmpty()) {
val user = it[0]
user.current = true
userRepository.updateUser(user)
result = user
}
} }
return null
return flowOf(result)
} }
override val currentUser: UserNgEntity? override val currentUser: Flow<UserNgEntity?>
get() { get() {
return userRepository.getActiveUser() return userRepository.getActiveUser()
} }
@ -71,59 +89,84 @@ class UserManager internal constructor(private val userRepository: UsersReposito
userRepository.deleteUserWithId(internalId) userRepository.deleteUserWithId(internalId)
} }
fun getUserById(userId: String): UserNgEntity? { fun getUserById(userId: String): Flow<UserNgEntity?> {
return userRepository.getUserWithUserId(userId) return userRepository.getUserWithUserId(userId)
} }
fun getUserWithId(id: Long): UserNgEntity? { fun getUserWithId(id: Long): Flow<UserNgEntity?> {
return userRepository.getUserWithId(id) return userRepository.getUserWithId(id)
} }
suspend fun disableAllUsersWithoutId(userId: Long) { suspend fun disableAllUsersWithoutId(userId: Long) {
val results = userRepository.getUsersWithoutUserId(userId) val results = userRepository.getUsersWithoutUserId(userId)
if (results.isNotEmpty()) {
for (entity in results) { results.collect {
entity.current = false if (it.isNotEmpty()) {
userRepository.updateUser(entity) for (entity in it) {
entity.current = false
userRepository.updateUser(entity)
}
} }
} }
} }
suspend fun checkIfUserIsScheduledForDeletion(username: String, server: String): Boolean { suspend fun checkIfUserIsScheduledForDeletion(username: String, server: String): Flow<Boolean> {
val results = userRepository.getUserWithUsernameAndServer(username, server) val results = userRepository.getUserWithUsernameAndServer(username, server)
return results?.scheduledForDeletion ?: false var result = FALSE
results.collect {
result = it?.scheduledForDeletion ?: FALSE
}
return flowOf(result)
} }
fun getUserWithInternalId(id: Long): UserNgEntity? { fun getUserWithInternalId(id: Long): Flow<UserNgEntity?> {
return userRepository.getUserWithIdNotScheduledForDeletion(id) return userRepository.getUserWithIdNotScheduledForDeletion(id)
} }
suspend fun getIfUserWithUsernameAndServer(username: String, server: String): Boolean { suspend fun getIfUserWithUsernameAndServer(username: String, server: String): Flow<Boolean> {
return userRepository.getUserWithUsernameAndServer(username, server) != null val results = userRepository.getUserWithUsernameAndServer(username, server)
} var result = FALSE
results.collect {
suspend fun scheduleUserForDeletionWithId(id: Long): Boolean { result = it != null
val result = userRepository.getUserWithId(id)
if (result != null) {
result.scheduledForDeletion = true
result.current = false
userRepository.updateUser(result)
} }
return setAnyUserAndSetAsActive() != null return flowOf(result)
}
suspend fun scheduleUserForDeletionWithId(id: Long): Flow<Boolean> {
val results = userRepository.getUserWithId(id)
var result = FALSE
results.collect {
if (it != null) {
it.scheduledForDeletion = true
it.current = false
userRepository.updateUser(it)
}
}
setAnyUserAndSetAsActive().collect {
result = it != null
}
return flowOf(result)
} }
suspend fun createOrUpdateUser( suspend fun createOrUpdateUser(
username: String?, username: String?,
userAttributes: UserAttributes, userAttributes: UserAttributes,
): LiveData<UserNgEntity?> { ): Flow<UserNgEntity?> {
var user = if (userAttributes.id == null && username != null && userAttributes.serverUrl != null) { var user: UserNgEntity? = null
userRepository.getUserWithUsernameAndServer(username, userAttributes.serverUrl)
if (userAttributes.id == null && username != null && userAttributes.serverUrl != null) {
userRepository.getUserWithUsernameAndServer(username, userAttributes.serverUrl).collect {
user = it
}
} else if (userAttributes.id != null) { } else if (userAttributes.id != null) {
userRepository.getUserWithId(userAttributes.id) userRepository.getUserWithId(userAttributes.id).collect {
} else { user = it
null }
} }
if (user == null) { if (user == null) {
@ -133,12 +176,13 @@ class UserManager internal constructor(private val userRepository: UsersReposito
) )
} else { } else {
updateUserData( updateUserData(
user, user!!,
userAttributes userAttributes
) )
} }
userRepository.insertUser(user)
return userRepository.getUserWithIdLiveData(user.id) userRepository.insertUser(user!!)
return userRepository.getUserWithIdLiveData(user!!.id)
} }
private fun updateUserData(user: UserNgEntity, userAttributes: UserAttributes) { private fun updateUserData(user: UserNgEntity, userAttributes: UserAttributes) {

View File

@ -21,7 +21,8 @@
package com.nextcloud.talk.utils.database.user package com.nextcloud.talk.utils.database.user
import com.nextcloud.talk.data.user.model.UserNgEntity import com.nextcloud.talk.data.user.model.UserNgEntity
import kotlinx.coroutines.flow.Flow
interface CurrentUserProviderNew { interface CurrentUserProviderNew {
val currentUser: UserNgEntity? val currentUser: Flow<UserNgEntity?>
} }

View File

@ -20,6 +20,8 @@
package com.nextcloud.talk.utils.database.user package com.nextcloud.talk.utils.database.user
import com.nextcloud.talk.dagger.modules.DatabaseModule import com.nextcloud.talk.dagger.modules.DatabaseModule
import com.nextcloud.talk.data.user.UsersRepository
import com.nextcloud.talk.users.UserManager
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@ -32,10 +34,18 @@ abstract class UserModule {
@Binds @Binds
abstract fun bindCurrentUserProvider(userUtils: UserUtils): CurrentUserProvider abstract fun bindCurrentUserProvider(userUtils: UserUtils): CurrentUserProvider
@Binds
abstract fun bindCurrentUserProviderNew(userManager: UserManager): CurrentUserProviderNew
companion object { companion object {
@Provides @Provides
fun provideUserUtils(dataStore: ReactiveEntityStore<Persistable?>?): UserUtils { fun provideUserUtils(dataStore: ReactiveEntityStore<Persistable?>?): UserUtils {
return UserUtils(dataStore) return UserUtils(dataStore)
} }
@Provides
fun provideUserManager(userRepository: UsersRepository): UserManager {
return UserManager(userRepository)
}
} }
} }