From 61469257572b57d484737acb3c1658aa0694438c Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 20 Nov 2020 10:16:56 +0100 Subject: [PATCH] Better error handling Rx call --- .../userdirectory/UserListViewModel.kt | 82 +++++++------------ 1 file changed, 30 insertions(+), 52 deletions(-) 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 1011a3e28a..b1d9e26afa 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 @@ -33,7 +33,9 @@ import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.rx.rx import java.util.concurrent.TimeUnit @@ -57,9 +59,6 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User companion object : MvRxViewModelFactory { - private val USER_NOT_FOUND_MAP = emptyMap() - private val USER_NOT_FOUND = User("") - override fun create(viewModelContext: ViewModelContext, state: UserListViewState): UserListViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory @@ -124,65 +123,44 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User } currentUserSearchDisposable?.dispose() + directoryUsersSearch .debounce(300, TimeUnit.MILLISECONDS) .switchMapSingle { search -> val stream = if (search.isBlank()) { - Single.just(emptyList()) - } else if (MatrixPatterns.isUserId(search)) { - // If it's a valid user id try to use Profile API - // because directory only returns users that are in public rooms or share a room with you, where as - // profile will work other federations - session.rx().searchUsersDirectory(search, 50, state.excludedUserIds ?: emptySet()) - .map { users -> - users.sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } - } - .zipWith( - session.rx().getProfileInfo(search) - // ... not sure how to handle that properly (manage error case in map and return optional) - .onErrorReturn { USER_NOT_FOUND_MAP } - .map { json -> - if (json === USER_NOT_FOUND_MAP) { - USER_NOT_FOUND - } else { - User( - userId = search, - displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String, - avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String - ) - } - }, - { t1, t2 -> - if (t2 == USER_NOT_FOUND) { - t1 - } - // profile result might also be in search results, in this case keep search result - else if (t1.indexOfFirst { it.userId == t2.userId } != -1) { - t1 - } else { - // put it first - listOf(t2) + t1 - } - } - ) - .doOnSubscribe { - currentUserSearchDisposable = it - } - .doOnDispose { - currentUserSearchDisposable = null - } + Single.just(emptyList()) } else { - session.rx() + val searchObservable = session.rx() .searchUsersDirectory(search, 50, state.excludedUserIds ?: emptySet()) .map { users -> users.sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } } - .doOnSubscribe { - currentUserSearchDisposable = it - } - .doOnDispose { - currentUserSearchDisposable = null + // If it's a valid user id try to use Profile API + // because directory only returns users that are in public rooms or share a room with you, where as + // profile will work other federations + if (!MatrixPatterns.isUserId(search)) { + searchObservable + } else { + val profileObservable = session.rx().getProfileInfo(search) + .map { json -> + User( + userId = search, + displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String, + avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String + ).toOptional() + } + .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 } + }) + } } stream.toAsync { copy(directoryUsers = it)