From 3705fa14bd863108e48b9e820f23ff00ad71cba8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 1 Oct 2020 17:03:53 +0200 Subject: [PATCH] Use sender data return from search result --- .../android/sdk/api/session/room/Room.kt | 1 + .../sdk/api/session/search/SearchResult.kt | 8 ++++- .../sdk/api/session/search/SearchService.kt | 1 + .../sdk/internal/session/search/SearchTask.kt | 18 ++++++++++- .../response/SearchResponseEventContext.kt | 2 +- .../home/room/detail/search/SearchActivity.kt | 3 +- .../home/room/detail/search/SearchFragment.kt | 5 ++-- .../detail/search/SearchResultController.kt | 20 +++++++------ .../room/detail/search/SearchResultItem.kt | 10 +++---- .../room/detail/search/SearchViewModel.kt | 30 +++++++++++-------- .../room/detail/search/SearchViewState.kt | 8 ++--- 11 files changed, 69 insertions(+), 37 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt index 86029e5419..9afff5f59c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt @@ -83,6 +83,7 @@ interface Room : * @param beforeLimit how many events before the result are returned. * @param afterLimit how many events after the result are returned. * @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned. + * @param callback Callback to get the search result */ fun search(searchTerm: String, nextBatch: String?, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchResult.kt index 59d1c4d46d..e95d7fab19 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchResult.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.search import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.util.MatrixItem /** * Domain class to represent the response of a search request in a room. @@ -35,5 +36,10 @@ data class SearchResult( /** * List of results in the requested order. */ - val results: List? = null + val results: List? = null +) + +data class EventAndSender( + val event: Event, + val sender: MatrixItem.UserItem? ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt index 0abbdfd958..a8c9e79ba9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt @@ -36,6 +36,7 @@ interface SearchService { * @param beforeLimit how many events before the result are returned. * @param afterLimit how many events after the result are returned. * @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned. + * @param callback Callback to get the search result */ fun search(searchTerm: String, roomId: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt index 3bb65fb8da..c90068e507 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt @@ -18,7 +18,9 @@ package org.matrix.android.sdk.internal.session.search import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.session.search.EventAndSender import org.matrix.android.sdk.api.session.search.SearchResult +import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody import org.matrix.android.sdk.internal.session.search.request.SearchRequestCategories @@ -76,7 +78,21 @@ internal class DefaultSearchTask @Inject constructor( return SearchResult( nextBatch = searchCategories.roomEvents?.nextBatch, highlights = searchCategories.roomEvents?.highlights, - results = searchCategories.roomEvents?.results?.map { it.event }?.reversed() + results = searchCategories.roomEvents?.results?.map { searchResponseItem -> + EventAndSender( + searchResponseItem.event, + searchResponseItem.event.senderId?.let { senderId -> + searchResponseItem.context?.profileInfo?.get(senderId) + ?.let { + MatrixItem.UserItem( + senderId, + it["displayname"] as? String, + it["avatar_url"] as? String + ) + } + } + ) + }?.reversed() ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseEventContext.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseEventContext.kt index 596645c355..f4d8699b2d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseEventContext.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseEventContext.kt @@ -38,5 +38,5 @@ internal data class SearchResponseEventContext( val end: String? = null, // The historic profile information of the users that sent the events returned. The string key is the user ID for which the profile belongs to. @Json(name = "profile_info") - val profileInfo: JsonDict? = null + val profileInfo: Map? = null ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt index 24069a37c3..f85dccbb27 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt @@ -70,7 +70,8 @@ class SearchActivity : VectorBaseActivity() { fun newIntent(context: Context, args: SearchArgs): Intent { return Intent(context, SearchActivity::class.java).apply { - flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT + // If we do that we will have the same room two times on the stack. Let's allow infinite stack for the moment. + // flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT putExtra(MvRx.KEY_ARG, args) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt index ea7ba8f464..666f5b3d38 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt @@ -90,7 +90,7 @@ class SearchFragment @Inject constructor( is Loading -> { stateView.state = StateView.State.Loading } - is Fail -> { + is Fail -> { stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error)) } is Success -> { @@ -100,8 +100,7 @@ class SearchFragment @Inject constructor( } } } else { - val lastBatchSize = state.lastBatch?.size ?: 0 - pendingScrollToPosition = if (lastBatchSize > 0) lastBatchSize - 1 else 0 + pendingScrollToPosition = (state.lastBatchSize - 1).coerceAtLeast(0) stateView.state = StateView.State.Content controller.setData(state) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt index 8daa4f60e4..c917c4557d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt @@ -25,6 +25,8 @@ import im.vector.app.core.ui.list.genericItemHeader import im.vector.app.features.home.AvatarRenderer import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.search.EventAndSender +import org.matrix.android.sdk.api.util.toMatrixItem import java.util.Calendar import javax.inject.Inject @@ -62,15 +64,15 @@ class SearchResultController @Inject constructor( } } - buildSearchResultItems(data.searchResult.orEmpty()) + buildSearchResultItems(data.searchResult) } - private fun buildSearchResultItems(events: List) { + private fun buildSearchResultItems(events: List) { var lastDate: Calendar? = null - events.forEach { event -> + events.forEach { eventAndSender -> val eventDate = Calendar.getInstance().apply { - timeInMillis = event.originServerTs ?: System.currentTimeMillis() + timeInMillis = eventAndSender.event.originServerTs ?: System.currentTimeMillis() } if (lastDate?.get(Calendar.DAY_OF_YEAR) != eventDate.get(Calendar.DAY_OF_YEAR)) { genericItemHeader { @@ -81,13 +83,13 @@ class SearchResultController @Inject constructor( lastDate = eventDate searchResultItem { - id(event.eventId) + id(eventAndSender.event.eventId) avatarRenderer(avatarRenderer) dateFormatter(dateFormatter) - event(event) - // I think we should use the data returned by the server? - sender(event.senderId?.let { session.getUser(it) }) - listener { listener?.onItemClicked(event) } + event(eventAndSender.event) + sender(eventAndSender.sender + ?: eventAndSender.event.senderId?.let { session.getUser(it) }?.toMatrixItem()) + listener { listener?.onItemClicked(eventAndSender.event) } } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt index 2d569c1c6a..10407c64e0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt @@ -27,10 +27,10 @@ import im.vector.app.core.epoxy.ClickListener import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.epoxy.onClick +import im.vector.app.core.extensions.setTextOrHide import im.vector.app.features.home.AvatarRenderer import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.session.user.model.User -import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.api.util.MatrixItem @EpoxyModelClass(layout = R.layout.item_search_result) abstract class SearchResultItem : VectorEpoxyModel() { @@ -38,15 +38,15 @@ abstract class SearchResultItem : VectorEpoxyModel() { @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute var dateFormatter: VectorDateFormatter? = null @EpoxyAttribute lateinit var event: Event - @EpoxyAttribute var sender: User? = null + @EpoxyAttribute var sender: MatrixItem? = null @EpoxyAttribute var listener: ClickListener? = null override fun bind(holder: Holder) { super.bind(holder) holder.view.onClick(listener) - sender?.toMatrixItem()?.let { avatarRenderer.render(it, holder.avatarImageView) } - holder.memberNameView.text = sender?.getBestName() + sender?.let { avatarRenderer.render(it, holder.avatarImageView) } + holder.memberNameView.setTextOrHide(sender?.getBestName()) holder.timeView.text = dateFormatter?.format(event.originServerTs, DateFormatKind.MESSAGE_SIMPLE) // TODO Improve that (use formattedBody, etc.) holder.contentView.text = event.content?.get("body") as? String 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 6703815f57..21a2d18e71 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 @@ -69,9 +69,14 @@ class SearchViewModel @AssistedInject constructor( } private fun handleSearchWith(action: SearchAction.SearchWith) { - if (action.searchTerm.length > 1) { + if (action.searchTerm.isNotEmpty()) { setState { - copy(searchTerm = action.searchTerm) + copy( + searchResult = emptyList(), + hasMoreResult = false, + lastBatchSize = 0, + searchTerm = action.searchTerm + ) } startSearching(false) } @@ -100,9 +105,7 @@ class SearchViewModel @AssistedInject constructor( } } - if (state.asyncSearchRequest is Loading) { - currentTask?.cancel() - } + currentTask?.cancel() viewModelScope.launch { try { @@ -118,24 +121,22 @@ class SearchViewModel @AssistedInject constructor( callback = it ) } - onSearchResultSuccess(result, isNextBatch) + onSearchResultSuccess(result) } catch (failure: Throwable) { if (failure is Failure.Cancelled) return@launch _viewEvents.post(SearchViewEvents.Failure(failure)) setState { copy( - asyncSearchRequest = Fail(failure), - searchResult = null + asyncSearchRequest = Fail(failure) ) } } } } - private fun onSearchResultSuccess(searchResult: SearchResult, isNextBatch: Boolean) = withState { state -> - // Accumulate results if it is the next batch - val accumulatedResult = searchResult.results.orEmpty().plus(state.searchResult?.takeIf { isNextBatch }.orEmpty()) + private fun onSearchResultSuccess(searchResult: SearchResult) = withState { state -> + val accumulatedResult = searchResult.results.orEmpty().plus(state.searchResult) // Note: We do not care about the highlights for the moment, but it will be the same algorithm @@ -145,9 +146,14 @@ class SearchViewModel @AssistedInject constructor( copy( searchResult = accumulatedResult, hasMoreResult = !nextBatch.isNullOrEmpty(), - lastBatch = searchResult.results, + lastBatchSize = searchResult.results.orEmpty().size, asyncSearchRequest = Success(Unit) ) } } + + override fun onCleared() { + currentTask?.cancel() + super.onCleared() + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt index 72da1ca940..9f700b6e31 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt @@ -19,14 +19,14 @@ package im.vector.app.features.home.room.detail.search import com.airbnb.mvrx.Async import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized -import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.search.EventAndSender data class SearchViewState( // Accumulated search result - val searchResult: List? = null, + val searchResult: List = emptyList(), val hasMoreResult: Boolean = false, - // Last batch result will help RecyclerView to position itself - val lastBatch: List? = null, + // Last batch size, will help RecyclerView to position itself + val lastBatchSize: Int = 0, val searchTerm: String? = null, val roomId: String = "", // Current pagination request