From e23cba1d2011b2531bafe1a3d7799b2b7ed596d4 Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Sat, 27 Mar 2021 20:14:59 +0000 Subject: [PATCH] Convert ProfileService to suspend functions Signed-off-by: Dominic Fischer --- .../org/matrix/android/sdk/rx/RxSession.kt | 5 +- .../sdk/api/session/profile/ProfileService.kt | 26 ++-- .../session/profile/DefaultProfileService.kt | 126 +++++------------- .../home/room/detail/RoomDetailViewModel.kt | 4 +- .../settings/VectorSettingsGeneralFragment.kt | 46 +++---- .../threepids/ThreePidsSettingsViewModel.kt | 82 ++++++------ 6 files changed, 108 insertions(+), 181 deletions(-) diff --git a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt index a7b269fcc6f..150a9dc9aa3 100644 --- a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt +++ b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxSession.kt @@ -20,6 +20,7 @@ import androidx.paging.PagedList import io.reactivex.Observable import io.reactivex.Single import io.reactivex.functions.Function3 +import kotlinx.coroutines.rx2.rxSingle import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session @@ -144,8 +145,8 @@ class RxSession(private val session: Session) { session.getRoomIdByAlias(roomAlias, searchOnServer, it) } - fun getProfileInfo(userId: String): Single = singleBuilder { - session.getProfile(userId, it) + fun getProfileInfo(userId: String): Single = rxSingle { + session.getProfile(userId) } fun liveUserCryptoDevices(userId: String): Observable> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt index a4d5b665c64..e493adeaf27 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt @@ -19,10 +19,8 @@ package org.matrix.android.sdk.api.session.profile import android.net.Uri import androidx.lifecycle.LiveData -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.identity.ThreePid -import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.Optional @@ -41,14 +39,14 @@ interface ProfileService { * @param userId the userId param to look for * */ - fun getDisplayName(userId: String, matrixCallback: MatrixCallback>): Cancelable + suspend fun getDisplayName(userId: String): Optional /** * Update the display name for this user * @param userId the userId to update the display name of * @param newDisplayName the new display name of the user */ - fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback): Cancelable + suspend fun setDisplayName(userId: String, newDisplayName: String) /** * Update the avatar for this user @@ -56,14 +54,14 @@ interface ProfileService { * @param newAvatarUri the new avatar uri of the user * @param fileName the fileName of selected image */ - fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback): Cancelable + suspend fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String) /** * Return the current avatarUrl for this user. * @param userId the userId param to look for * */ - fun getAvatarUrl(userId: String, matrixCallback: MatrixCallback>): Cancelable + suspend fun getAvatarUrl(userId: String): Optional /** * Get the combined profile information for this user. @@ -71,7 +69,7 @@ interface ProfileService { * @param userId the userId param to look for * */ - fun getProfile(userId: String, matrixCallback: MatrixCallback): Cancelable + suspend fun getProfile(userId: String): JsonDict /** * Get the current user 3Pids @@ -97,28 +95,26 @@ interface ProfileService { /** * Add a 3Pids. This is the first step to add a ThreePid to an account. Then the threePid will be added to the pending threePid list. */ - fun addThreePid(threePid: ThreePid, matrixCallback: MatrixCallback): Cancelable + suspend fun addThreePid(threePid: ThreePid) /** * Validate a code received by text message */ - fun submitSmsCode(threePid: ThreePid.Msisdn, code: String, matrixCallback: MatrixCallback): Cancelable + suspend fun submitSmsCode(threePid: ThreePid.Msisdn, code: String) /** * Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid */ - fun finalizeAddingThreePid(threePid: ThreePid, - userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, - matrixCallback: MatrixCallback): Cancelable + suspend fun finalizeAddingThreePid(threePid: ThreePid, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) /** * Cancel adding a threepid. It will remove locally stored data about this ThreePid */ - fun cancelAddingThreePid(threePid: ThreePid, - matrixCallback: MatrixCallback): Cancelable + suspend fun cancelAddingThreePid(threePid: ThreePid) /** * Remove a 3Pid from the Matrix account. */ - fun deleteThreePid(threePid: ThreePid, matrixCallback: MatrixCallback): Cancelable + suspend fun deleteThreePid(threePid: ThreePid) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt index b3216d744d4..386fec8256f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt @@ -21,11 +21,10 @@ import android.net.Uri import androidx.lifecycle.LiveData import com.zhuinden.monarchy.Monarchy import io.realm.kotlin.where -import org.matrix.android.sdk.api.MatrixCallback +import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.profile.ProfileService -import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.MimeTypes import org.matrix.android.sdk.api.util.Optional @@ -36,7 +35,6 @@ import org.matrix.android.sdk.internal.session.content.FileUploader import org.matrix.android.sdk.internal.session.user.UserStore import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith -import org.matrix.android.sdk.internal.task.launchToCallback import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject @@ -55,64 +53,38 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto private val userStore: UserStore, private val fileUploader: FileUploader) : ProfileService { - override fun getDisplayName(userId: String, matrixCallback: MatrixCallback>): Cancelable { + override suspend fun getDisplayName(userId: String): Optional { val params = GetProfileInfoTask.Params(userId) - return getProfileInfoTask - .configureWith(params) { - this.callback = object : MatrixCallback { - override fun onSuccess(data: JsonDict) { - val displayName = data[ProfileService.DISPLAY_NAME_KEY] as? String - matrixCallback.onSuccess(Optional.from(displayName)) - } - - override fun onFailure(failure: Throwable) { - matrixCallback.onFailure(failure) - } - } - } - .executeBy(taskExecutor) + val data = getProfileInfoTask.execute(params) + val displayName = data[ProfileService.DISPLAY_NAME_KEY] as? String + return Optional.from(displayName) } - override fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback): Cancelable { - return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.io, matrixCallback) { + override suspend fun setDisplayName(userId: String, newDisplayName: String) { + withContext(coroutineDispatchers.io) { setDisplayNameTask.execute(SetDisplayNameTask.Params(userId = userId, newDisplayName = newDisplayName)) userStore.updateDisplayName(userId, newDisplayName) } } - override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback): Cancelable { - return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, matrixCallback) { + override suspend fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String) { + withContext(coroutineDispatchers.main) { val response = fileUploader.uploadFromUri(newAvatarUri, fileName, MimeTypes.Jpeg) setAvatarUrlTask.execute(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = response.contentUri)) userStore.updateAvatar(userId, response.contentUri) } } - override fun getAvatarUrl(userId: String, matrixCallback: MatrixCallback>): Cancelable { + override suspend fun getAvatarUrl(userId: String): Optional { val params = GetProfileInfoTask.Params(userId) - return getProfileInfoTask - .configureWith(params) { - this.callback = object : MatrixCallback { - override fun onSuccess(data: JsonDict) { - val avatarUrl = data[ProfileService.AVATAR_URL_KEY] as? String - matrixCallback.onSuccess(Optional.from(avatarUrl)) - } - - override fun onFailure(failure: Throwable) { - matrixCallback.onFailure(failure) - } - } - } - .executeBy(taskExecutor) + val data = getProfileInfoTask.execute(params) + val avatarUrl = data[ProfileService.AVATAR_URL_KEY] as? String + return Optional.from(avatarUrl) } - override fun getProfile(userId: String, matrixCallback: MatrixCallback): Cancelable { + override suspend fun getProfile(userId: String): JsonDict { val params = GetProfileInfoTask.Params(userId) - return getProfileInfoTask - .configureWith(params) { - this.callback = matrixCallback - } - .executeBy(taskExecutor) + return getProfileInfoTask.execute(params) } override fun getThreePids(): List { @@ -154,70 +126,38 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto ) } - override fun addThreePid(threePid: ThreePid, matrixCallback: MatrixCallback): Cancelable { - return addThreePidTask - .configureWith(AddThreePidTask.Params(threePid)) { - callback = matrixCallback - } - .executeBy(taskExecutor) + override suspend fun addThreePid(threePid: ThreePid) { + addThreePidTask.execute(AddThreePidTask.Params(threePid)) } - override fun submitSmsCode(threePid: ThreePid.Msisdn, code: String, matrixCallback: MatrixCallback): Cancelable { - return validateSmsCodeTask - .configureWith(ValidateSmsCodeTask.Params(threePid, code)) { - callback = matrixCallback - } - .executeBy(taskExecutor) + override suspend fun submitSmsCode(threePid: ThreePid.Msisdn, code: String) { + validateSmsCodeTask.execute(ValidateSmsCodeTask.Params(threePid, code)) } - override fun finalizeAddingThreePid(threePid: ThreePid, - userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, - matrixCallback: MatrixCallback): Cancelable { - return finalizeAddingThreePidTask - .configureWith(FinalizeAddingThreePidTask.Params( + override suspend fun finalizeAddingThreePid(threePid: ThreePid, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) { + finalizeAddingThreePidTask + .execute(FinalizeAddingThreePidTask.Params( threePid = threePid, userInteractiveAuthInterceptor = userInteractiveAuthInterceptor, userWantsToCancel = false - )) { - callback = alsoRefresh(matrixCallback) - } - .executeBy(taskExecutor) + )) + refreshThreePids() } - override fun cancelAddingThreePid(threePid: ThreePid, matrixCallback: MatrixCallback): Cancelable { - return finalizeAddingThreePidTask - .configureWith(FinalizeAddingThreePidTask.Params( + override suspend fun cancelAddingThreePid(threePid: ThreePid) { + finalizeAddingThreePidTask + .execute(FinalizeAddingThreePidTask.Params( threePid = threePid, userInteractiveAuthInterceptor = null, userWantsToCancel = true - )) { - callback = alsoRefresh(matrixCallback) - } - .executeBy(taskExecutor) - } - - /** - * Wrap the callback to fetch 3Pids from the server in case of success - */ - private fun alsoRefresh(callback: MatrixCallback): MatrixCallback { - return object : MatrixCallback { - override fun onFailure(failure: Throwable) { - callback.onFailure(failure) - } - - override fun onSuccess(data: Unit) { - refreshThreePids() - callback.onSuccess(data) - } - } + )) + refreshThreePids() } - override fun deleteThreePid(threePid: ThreePid, matrixCallback: MatrixCallback): Cancelable { - return deleteThreePidTask - .configureWith(DeleteThreePidTask.Params(threePid)) { - callback = alsoRefresh(matrixCallback) - } - .executeBy(taskExecutor) + override suspend fun deleteThreePid(threePid: ThreePid) { + deleteThreePidTask.execute(DeleteThreePidTask.Params(threePid)) + refreshThreePids() } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index af3d5461efa..2f099e72842 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -965,8 +965,8 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun handleChangeDisplayNameSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayName) { - launchSlashCommandFlow { - session.setDisplayName(session.myUserId, changeDisplayName.displayName, it) + launchSlashCommandFlowSuspendable { + session.setDisplayName(session.myUserId, changeDisplayName.displayName) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index b66a37b75f7..334464e304c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -55,7 +55,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerConfig import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService @@ -305,17 +304,13 @@ class VectorSettingsGeneralFragment @Inject constructor( private fun uploadAvatar(uri: Uri) { displayLoadingView() - session.updateAvatar(session.myUserId, uri, getFilenameFromUri(context, uri) ?: UUID.randomUUID().toString(), object : MatrixCallback { - override fun onSuccess(data: Unit) { - if (!isAdded) return - onCommonDone(null) + lifecycleScope.launch { + val result = runCatching { + session.updateAvatar(session.myUserId, uri, getFilenameFromUri(context, uri) ?: UUID.randomUUID().toString()) } - - override fun onFailure(failure: Throwable) { - if (!isAdded) return - onCommonDone(failure.localizedMessage) - } - }) + if (!isAdded) return@launch + onCommonDone(result.fold({ null }, { it.localizedMessage })) + } } // ============================================================================================================== @@ -477,20 +472,21 @@ class VectorSettingsGeneralFragment @Inject constructor( if (currentDisplayName != value) { displayLoadingView() - session.setDisplayName(session.myUserId, value, object : MatrixCallback { - override fun onSuccess(data: Unit) { - if (!isAdded) return - // refresh the settings value - mDisplayNamePreference.summary = value - mDisplayNamePreference.text = value - onCommonDone(null) - } - - override fun onFailure(failure: Throwable) { - if (!isAdded) return - onCommonDone(failure.localizedMessage) - } - }) + lifecycleScope.launch { + val result = runCatching { session.setDisplayName(session.myUserId, value) } + if (!isAdded) return@launch + result.fold( + { + // refresh the settings value + mDisplayNamePreference.summary = value + mDisplayNamePreference.text = value + onCommonDone(null) + }, + { + onCommonDone(it.localizedMessage) + } + ) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt index 89d632b813d..ac565e72a1a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt @@ -33,7 +33,6 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.ReadOnceTrue import im.vector.app.features.auth.ReAuthActivity import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.session.Session @@ -58,16 +57,18 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( private var pendingThreePid: ThreePid? = null // private var pendingSession: String? = null - private val loadingCallback: MatrixCallback = object : MatrixCallback { - override fun onFailure(failure: Throwable) { - isLoading(false) - _viewEvents.post(ThreePidsSettingsViewEvents.Failure(failure)) - } - - override fun onSuccess(data: Unit) { - pendingThreePid = null - isLoading(false) - } + private suspend fun loadingSuspendable(block: suspend () -> Unit) { + runCatching { block() } + .fold( + { + pendingThreePid = null + isLoading(false) + }, + { + isLoading(false) + _viewEvents.post(ThreePidsSettingsViewEvents.Failure(it)) + } + ) } private fun isLoading(isLoading: Boolean) { @@ -186,24 +187,23 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( viewModelScope.launch { // First submit the code - session.submitSmsCode(action.threePid, action.code, object : MatrixCallback { - override fun onSuccess(data: Unit) { - // then finalize - pendingThreePid = action.threePid - session.finalizeAddingThreePid(action.threePid, uiaInterceptor, loadingCallback) + try { + session.submitSmsCode(action.threePid, action.code) + } catch (failure: Throwable) { + isLoading(false) + setState { + copy( + msisdnValidationRequests = msisdnValidationRequests.toMutableMap().apply { + put(action.threePid.value, Fail(failure)) + } + ) } + return@launch + } - override fun onFailure(failure: Throwable) { - isLoading(false) - setState { - copy( - msisdnValidationRequests = msisdnValidationRequests.toMutableMap().apply { - put(action.threePid.value, Fail(failure)) - } - ) - } - } - }) + // then finalize + pendingThreePid = action.threePid + loadingSuspendable { session.finalizeAddingThreePid(action.threePid, uiaInterceptor) } } } @@ -230,21 +230,15 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( )))) } else { viewModelScope.launch { - session.addThreePid(action.threePid, object : MatrixCallback { - override fun onSuccess(data: Unit) { - // Also reset the state - setState { - copy( - uiState = ThreePidsSettingsUiState.Idle - ) - } - loadingCallback.onSuccess(data) - } - - override fun onFailure(failure: Throwable) { - loadingCallback.onFailure(failure) + loadingSuspendable { + session.addThreePid(action.threePid) + // Also reset the state + setState { + copy( + uiState = ThreePidsSettingsUiState.Idle + ) } - }) + } } } } @@ -254,14 +248,14 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( isLoading(true) pendingThreePid = action.threePid viewModelScope.launch { - session.finalizeAddingThreePid(action.threePid, uiaInterceptor, loadingCallback) + loadingSuspendable { session.finalizeAddingThreePid(action.threePid, uiaInterceptor) } } } private fun handleCancelThreePid(action: ThreePidsSettingsAction.CancelThreePid) { isLoading(true) viewModelScope.launch { - session.cancelAddingThreePid(action.threePid, loadingCallback) + loadingSuspendable { session.cancelAddingThreePid(action.threePid) } } } @@ -277,7 +271,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( private fun handleDeleteThreePid(action: ThreePidsSettingsAction.DeleteThreePid) { isLoading(true) viewModelScope.launch { - session.deleteThreePid(action.threePid, loadingCallback) + loadingSuspendable { session.deleteThreePid(action.threePid) } } } }