diff --git a/CHANGES.md b/CHANGES.md index 21e0d3075b..b447b6e6e5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,8 @@ Improvements 🙌: Bugfix 🐛: - Message states cosmetic changes (#3007) + - Fix exception in rxSingle (#3180) + - Do not invite the current user when creating a room (#3123) - Fix color issues when the system theme is changed (#2738) Translations 🗣: diff --git a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxCallbackBuilders.kt b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxCallbackBuilders.kt deleted file mode 100644 index ec30a31f6d..0000000000 --- a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxCallbackBuilders.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2020 The Matrix.org Foundation C.I.C. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.matrix.android.sdk.rx - -import org.matrix.android.sdk.api.MatrixCallback -import org.matrix.android.sdk.api.util.Cancelable -import io.reactivex.Completable -import io.reactivex.Single - -fun singleBuilder(builder: (MatrixCallback) -> Cancelable): Single = Single.create { emitter -> - val callback = object : MatrixCallback { - override fun onSuccess(data: T) { - // Add `!!` to fix the warning: - // "Type mismatch: type parameter with nullable bounds is used T is used where T was expected. This warning will become an error soon" - emitter.onSuccess(data!!) - } - - override fun onFailure(failure: Throwable) { - emitter.tryOnError(failure) - } - } - val cancelable = builder(callback) - emitter.setCancellable { - cancelable.cancel() - } -} - -fun completableBuilder(builder: (MatrixCallback) -> Cancelable): Completable = Completable.create { emitter -> - val callback = object : MatrixCallback { - override fun onSuccess(data: T) { - emitter.onComplete() - } - - override fun onFailure(failure: Throwable) { - emitter.tryOnError(failure) - } - } - val cancelable = builder(callback) - emitter.setCancellable { - cancelable.cancel() - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt index b241903364..8f1bbb6941 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt @@ -32,7 +32,6 @@ import java.io.IOException */ sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) { data class Unknown(val throwable: Throwable? = null) : Failure(throwable) - data class Cancelled(val throwable: Throwable? = null) : Failure(throwable) data class UnrecognizedCertificateFailure(val url: String, val fingerprint: Fingerprint) : Failure() data class NetworkConnection(val ioException: IOException? = null) : Failure(ioException) data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString())) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt index 0246bae024..e045cebd3e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt @@ -88,8 +88,8 @@ internal suspend inline fun executeRequest(globalErrorReceiver: GlobalErr throw when (exception) { is IOException -> Failure.NetworkConnection(exception) is Failure.ServerError, - is Failure.OtherServerError -> exception - is CancellationException -> Failure.Cancelled(exception) + is Failure.OtherServerError, + is CancellationException -> exception else -> Failure.Unknown(exception) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index 5e823fc87f..80be49de61 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -27,6 +27,7 @@ import org.matrix.android.sdk.api.util.MimeTypes import org.matrix.android.sdk.internal.crypto.DeviceListManager import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.di.AuthenticatedIdentity +import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.token.AccessTokenProvider import org.matrix.android.sdk.internal.session.content.FileUploader import org.matrix.android.sdk.internal.session.identity.EnsureIdentityTokenTask @@ -43,6 +44,8 @@ internal class CreateRoomBodyBuilder @Inject constructor( private val deviceListManager: DeviceListManager, private val identityStore: IdentityStore, private val fileUploader: FileUploader, + @UserId + private val userId: String, @AuthenticatedIdentity private val accessTokenProvider: AccessTokenProvider ) { @@ -80,7 +83,7 @@ internal class CreateRoomBodyBuilder @Inject constructor( roomAliasName = params.roomAliasName, name = params.name, topic = params.topic, - invitedUserIds = params.invitedUserIds, + invitedUserIds = params.invitedUserIds.filter { it != userId }, invite3pids = invite3pids, creationContent = params.creationContent.takeIf { it.isNotEmpty() }, initialStates = initialStates, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt index 424c24663c..de8d009892 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt @@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer import com.squareup.moshi.JsonEncodingException +import kotlinx.coroutines.CancellationException import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.isTokenError import org.matrix.android.sdk.api.session.sync.SyncState @@ -199,7 +200,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, if (failure is Failure.NetworkConnection && failure.cause is SocketTimeoutException) { // Timeout are not critical Timber.v("Timeout") - } else if (failure is Failure.Cancelled) { + } else if (failure is CancellationException) { Timber.v("Cancelled") } else if (failure.isTokenError()) { // No token or invalid token, stop the thread diff --git a/vector/src/main/java/im/vector/app/core/mvrx/ResultExtension.kt b/vector/src/main/java/im/vector/app/core/mvrx/ResultExtension.kt new file mode 100644 index 0000000000..dfd04ea6f6 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/mvrx/ResultExtension.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.mvrx + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Success + +/** + * Note: this will be removed when upgrading to mvrx2 + */ +suspend fun runCatchingToAsync(block: suspend () -> A): Async { + return runCatching { + block.invoke() + }.fold( + { Success(it) }, + { Fail(it) } + ) +} diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index cbe363aa0e..2f0b6e5ec9 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -19,6 +19,7 @@ package im.vector.app.features.createdirect import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.Loading import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext @@ -26,6 +27,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import dagger.assisted.AssistedFactory import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.mvrx.runCatchingToAsync import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.isE2EByDefault @@ -35,7 +37,6 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams -import org.matrix.android.sdk.rx.rx class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateDirectRoomViewState, @@ -82,6 +83,8 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted } private fun createRoomAndInviteSelectedUsers(selections: Set) { + setState { copy(createAndInviteState = Loading()) } + viewModelScope.launch(Dispatchers.IO) { val adminE2EByDefault = rawService.getElementWellknown(session.myUserId) ?.isE2EByDefault() @@ -99,11 +102,15 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault } - session.rx() - .createRoom(roomParams) - .execute { - copy(createAndInviteState = it) - } + val result = runCatchingToAsync { + session.createRoom(roomParams) + } + + setState { + copy( + createAndInviteState = result + ) + } } } } 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 f0732d8f07..006a2c9b5f 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 @@ -35,6 +35,7 @@ import dagger.assisted.AssistedInject import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.mvrx.runCatchingToAsync import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.call.dialpad.DialPadLookup @@ -649,12 +650,15 @@ class RoomDetailViewModel @AssistedInject constructor( val viaServers = MatrixPatterns.extractServerNameFromId(action.event.senderId) ?.let { listOf(it) } .orEmpty() - session.rx() - .joinRoom(roomId, viaServers = viaServers) - .map { roomId } - .execute { - copy(tombstoneEventHandling = it) - } + viewModelScope.launch { + val result = runCatchingToAsync { + session.joinRoom(roomId, viaServers = viaServers) + roomId + } + setState { + copy(tombstoneEventHandling = result) + } + } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt index fb3abf002e..26111e4f2b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt @@ -28,9 +28,9 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.search.SearchResult @@ -120,7 +120,7 @@ class SearchViewModel @AssistedInject constructor( ) onSearchResultSuccess(result) } catch (failure: Throwable) { - if (failure is Failure.Cancelled) return@launch + if (failure is CancellationException) return@launch _viewEvents.post(SearchViewEvents.Failure(failure)) setState { diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt index 55730ff4ec..2f20fef3c9 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt @@ -92,6 +92,6 @@ class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted } fun getUserIdsOfRoomMembers(): Set { - return room.roomSummary()?.otherMemberIds?.toSet() ?: emptySet() + return room.roomSummary()?.otherMemberIds?.toSet().orEmpty() } } diff --git a/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt index e537f31e78..c16c7c6645 100644 --- a/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt @@ -29,6 +29,7 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment +import kotlinx.coroutines.CancellationException import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.MatrixError import javax.net.ssl.HttpsURLConnection @@ -76,7 +77,7 @@ abstract class AbstractLoginFragment : VectorBaseFragment() } when (throwable) { - is Failure.Cancelled -> + is CancellationException -> /* Ignore this error, user has cancelled the action */ Unit is Failure.ServerError -> diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt index a7d69c783c..ae6d630c75 100644 --- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt +++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt @@ -112,7 +112,10 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti private fun PermalinkData.RoomLink.getRoomId(): Single> { val session = activeSessionHolder.getSafeActiveSession() return if (isRoomAlias && session != null) { - session.rx().getRoomIdByAlias(roomIdOrAlias, true).map { it.getOrNull()?.roomId.toOptional() }.subscribeOn(Schedulers.io()) + session.rx() + .getRoomIdByAlias(roomIdOrAlias, true) + .map { it.getOrNull()?.roomId.toOptional() } + .subscribeOn(Schedulers.io()) } else { Single.just(Optional.from(roomIdOrAlias)) } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt index 7b55e38764..f64105b759 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt @@ -29,10 +29,10 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.settings.VectorPreferences +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse -import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter @@ -87,7 +87,7 @@ class RoomDirectoryViewModel @AssistedInject constructor( val joinedRoomIds = list ?.map { it.roomId } ?.toSet() - ?: emptySet() + .orEmpty() setState { copy(joinedRoomsIds = joinedRoomIds) @@ -183,7 +183,7 @@ class RoomDirectoryViewModel @AssistedInject constructor( ) ) } catch (failure: Throwable) { - if (failure is Failure.Cancelled) { + if (failure is CancellationException) { // Ignore, another request should be already started return@launch } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt index 64081a1683..7b05c6c7f5 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt @@ -29,6 +29,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import dagger.assisted.AssistedFactory import im.vector.app.R +import im.vector.app.core.mvrx.runCatchingToAsync import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.powerlevel.PowerLevelsObservableFactory @@ -139,7 +140,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v override fun handle(action: RoomMemberProfileAction) { when (action) { - is RoomMemberProfileAction.RetryFetchingInfo -> fetchProfileInfo() + is RoomMemberProfileAction.RetryFetchingInfo -> handleRetryFetchProfileInfo() is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction() is RoomMemberProfileAction.VerifyUser -> prepareVerification() is RoomMemberProfileAction.ShareRoomMemberProfile -> handleShareRoomMemberProfile() @@ -259,18 +260,27 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v } } - private fun fetchProfileInfo() { - session.rx().getProfileInfo(initialState.userId) - .map { - MatrixItem.UserItem( - id = initialState.userId, - displayName = it[ProfileService.DISPLAY_NAME_KEY] as? String, - avatarUrl = it[ProfileService.AVATAR_URL_KEY] as? String - ) - } - .execute { - copy(userMatrixItem = it) - } + private fun handleRetryFetchProfileInfo() { + viewModelScope.launch { + fetchProfileInfo() + } + } + + private suspend fun fetchProfileInfo() { + val result = runCatchingToAsync { + session.getProfile(initialState.userId) + .let { + MatrixItem.UserItem( + id = initialState.userId, + displayName = it[ProfileService.DISPLAY_NAME_KEY] as? String, + avatarUrl = it[ProfileService.AVATAR_URL_KEY] as? String + ) + } + } + + setState { + copy(userMatrixItem = result) + } } private fun observeRoomSummaryAndPowerLevels(room: Room) { diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt index a7ec9cd8c3..90fb828663 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt @@ -109,33 +109,37 @@ class UserListController @Inject constructor(private val session: Session, } private fun buildKnownUsers(currentState: UserListViewState, selectedUsers: List) { - currentState.knownUsers()?.let { userList -> - userListHeaderItem { - id("known_header") - header(stringProvider.getString(R.string.direct_room_user_list_known_title)) - } + currentState.knownUsers() + ?.filter { it.userId != session.myUserId } + ?.let { userList -> + userListHeaderItem { + id("known_header") + header(stringProvider.getString(R.string.direct_room_user_list_known_title)) + } - if (userList.isEmpty()) { - renderEmptyState() - return - } - userList.forEach { item -> - val isSelected = selectedUsers.contains(item.userId) - userDirectoryUserItem { - id(item.userId) - selected(isSelected) - matrixItem(item.toMatrixItem()) - avatarRenderer(avatarRenderer) - clickListener { _ -> - callback?.onItemClick(item) + if (userList.isEmpty()) { + renderEmptyState() + return + } + userList.forEach { item -> + val isSelected = selectedUsers.contains(item.userId) + userDirectoryUserItem { + id(item.userId) + selected(isSelected) + matrixItem(item.toMatrixItem()) + avatarRenderer(avatarRenderer) + clickListener { _ -> + callback?.onItemClick(item) + } + } } } - } - } } private fun buildDirectoryUsers(directoryUsers: List, selectedUsers: List, searchTerms: String, ignoreIds: List) { - val toDisplay = directoryUsers.filter { !ignoreIds.contains(it.userId) } + val toDisplay = directoryUsers + .filter { !ignoreIds.contains(it.userId) && it.userId != session.myUserId } + if (toDisplay.isEmpty() && searchTerms.isBlank()) { return } @@ -147,16 +151,14 @@ class UserListController @Inject constructor(private val session: Session, renderEmptyState() } else { toDisplay.forEach { user -> - if (user.userId != session.myUserId) { - val isSelected = selectedUsers.contains(user.userId) - userDirectoryUserItem { - id(user.userId) - selected(isSelected) - matrixItem(user.toMatrixItem()) - avatarRenderer(avatarRenderer) - clickListener { _ -> - callback?.onItemClick(user) - } + val isSelected = selectedUsers.contains(user.userId) + userDirectoryUserItem { + id(user.userId) + selected(isSelected) + matrixItem(user.toMatrixItem()) + avatarRenderer(avatarRenderer) + clickListener { _ -> + callback?.onItemClick(user) } } } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt index 4a87d13021..6e6df7a7aa 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt @@ -89,7 +89,7 @@ class UserListFragment @Inject constructor( viewModel.observeViewEvents { when (it) { - is UserListViewEvents.OpenShareMatrixToLing -> { + is UserListViewEvents.OpenShareMatrixToLink -> { val text = getString(R.string.invite_friends_text, it.link) startSharePlainTextIntent( fragment = this, diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt index 95c6729fad..f5ec044597 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt @@ -22,5 +22,5 @@ import im.vector.app.core.platform.VectorViewEvents * Transient events for invite users to room screen */ sealed class UserListViewEvents : VectorViewEvents { - data class OpenShareMatrixToLing(val link: String) : UserListViewEvents() + data class OpenShareMatrixToLink(val link: String) : UserListViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt index 0e042c8bc1..a68717ea57 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -29,7 +29,6 @@ import im.vector.app.core.extensions.toggle import im.vector.app.core.platform.VectorViewModel import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.Disposable import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.profile.ProfileService @@ -50,8 +49,6 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User private val knownUsersSearch = BehaviorRelay.create() private val directoryUsersSearch = BehaviorRelay.create() - private var currentUserSearchDisposable: Disposable? = null - @AssistedFactory interface Factory { fun create(initialState: UserListViewState): UserListViewModel @@ -92,7 +89,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User private fun handleShareMyMatrixToLink() { session.permalinkService().createPermalink(session.myUserId)?.let { - _viewEvents.post(UserListViewEvents.OpenShareMatrixToLing(it)) + _viewEvents.post(UserListViewEvents.OpenShareMatrixToLink(it)) } } @@ -115,8 +112,6 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User copy(knownUsers = async) } - currentUserSearchDisposable?.dispose() - directoryUsersSearch .debounce(300, TimeUnit.MILLISECONDS) .switchMapSingle { search -> @@ -124,7 +119,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User Single.just(emptyList()) } else { val searchObservable = session.rx() - .searchUsersDirectory(search, 50, state.excludedUserIds ?: emptySet()) + .searchUsersDirectory(search, 50, state.excludedUserIds.orEmpty()) .map { users -> users.sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } } @@ -144,15 +139,19 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User } .onErrorReturn { Optional.empty() } - Single.zip(searchObservable, profileObservable, { searchResults, optionalProfile -> - val profile = optionalProfile.getOrNull() ?: return@zip searchResults - val searchContainsProfile = searchResults.indexOfFirst { it.userId == profile.userId } != -1 - if (searchContainsProfile) { - searchResults - } else { - listOf(profile) + searchResults - } - }) + Single.zip( + searchObservable, + profileObservable, + { searchResults, optionalProfile -> + val profile = optionalProfile.getOrNull() ?: return@zip searchResults + val searchContainsProfile = searchResults.any { it.userId == profile.userId } + if (searchContainsProfile) { + searchResults + } else { + listOf(profile) + searchResults + } + } + ) } } stream.toAsync {