Use sender data return from search result
This commit is contained in:
parent
4649b2ac1d
commit
3705fa14bd
@ -83,6 +83,7 @@ interface Room :
|
|||||||
* @param beforeLimit how many events before the result are returned.
|
* @param beforeLimit how many events before the result are returned.
|
||||||
* @param afterLimit how many events after 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 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,
|
fun search(searchTerm: String,
|
||||||
nextBatch: String?,
|
nextBatch: String?,
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package org.matrix.android.sdk.api.session.search
|
package org.matrix.android.sdk.api.session.search
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
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.
|
* 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.
|
* List of results in the requested order.
|
||||||
*/
|
*/
|
||||||
val results: List<Event>? = null
|
val results: List<EventAndSender>? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
data class EventAndSender(
|
||||||
|
val event: Event,
|
||||||
|
val sender: MatrixItem.UserItem?
|
||||||
)
|
)
|
||||||
|
@ -36,6 +36,7 @@ interface SearchService {
|
|||||||
* @param beforeLimit how many events before the result are returned.
|
* @param beforeLimit how many events before the result are returned.
|
||||||
* @param afterLimit how many events after 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 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,
|
fun search(searchTerm: String,
|
||||||
roomId: String,
|
roomId: String,
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
package org.matrix.android.sdk.internal.session.search
|
package org.matrix.android.sdk.internal.session.search
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
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.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.network.executeRequest
|
||||||
import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody
|
import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody
|
||||||
import org.matrix.android.sdk.internal.session.search.request.SearchRequestCategories
|
import org.matrix.android.sdk.internal.session.search.request.SearchRequestCategories
|
||||||
@ -76,7 +78,21 @@ internal class DefaultSearchTask @Inject constructor(
|
|||||||
return SearchResult(
|
return SearchResult(
|
||||||
nextBatch = searchCategories.roomEvents?.nextBatch,
|
nextBatch = searchCategories.roomEvents?.nextBatch,
|
||||||
highlights = searchCategories.roomEvents?.highlights,
|
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()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,5 +38,5 @@ internal data class SearchResponseEventContext(
|
|||||||
val end: String? = null,
|
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.
|
// 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")
|
@Json(name = "profile_info")
|
||||||
val profileInfo: JsonDict? = null
|
val profileInfo: Map<String, JsonDict>? = null
|
||||||
)
|
)
|
||||||
|
@ -70,7 +70,8 @@ class SearchActivity : VectorBaseActivity() {
|
|||||||
|
|
||||||
fun newIntent(context: Context, args: SearchArgs): Intent {
|
fun newIntent(context: Context, args: SearchArgs): Intent {
|
||||||
return Intent(context, SearchActivity::class.java).apply {
|
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)
|
putExtra(MvRx.KEY_ARG, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ class SearchFragment @Inject constructor(
|
|||||||
is Loading -> {
|
is Loading -> {
|
||||||
stateView.state = StateView.State.Loading
|
stateView.state = StateView.State.Loading
|
||||||
}
|
}
|
||||||
is Fail -> {
|
is Fail -> {
|
||||||
stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error))
|
stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error))
|
||||||
}
|
}
|
||||||
is Success -> {
|
is Success -> {
|
||||||
@ -100,8 +100,7 @@ class SearchFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val lastBatchSize = state.lastBatch?.size ?: 0
|
pendingScrollToPosition = (state.lastBatchSize - 1).coerceAtLeast(0)
|
||||||
pendingScrollToPosition = if (lastBatchSize > 0) lastBatchSize - 1 else 0
|
|
||||||
|
|
||||||
stateView.state = StateView.State.Content
|
stateView.state = StateView.State.Content
|
||||||
controller.setData(state)
|
controller.setData(state)
|
||||||
|
@ -25,6 +25,8 @@ import im.vector.app.core.ui.list.genericItemHeader
|
|||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import org.matrix.android.sdk.api.session.Session
|
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.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 java.util.Calendar
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -62,15 +64,15 @@ class SearchResultController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSearchResultItems(data.searchResult.orEmpty())
|
buildSearchResultItems(data.searchResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildSearchResultItems(events: List<Event>) {
|
private fun buildSearchResultItems(events: List<EventAndSender>) {
|
||||||
var lastDate: Calendar? = null
|
var lastDate: Calendar? = null
|
||||||
|
|
||||||
events.forEach { event ->
|
events.forEach { eventAndSender ->
|
||||||
val eventDate = Calendar.getInstance().apply {
|
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)) {
|
if (lastDate?.get(Calendar.DAY_OF_YEAR) != eventDate.get(Calendar.DAY_OF_YEAR)) {
|
||||||
genericItemHeader {
|
genericItemHeader {
|
||||||
@ -81,13 +83,13 @@ class SearchResultController @Inject constructor(
|
|||||||
lastDate = eventDate
|
lastDate = eventDate
|
||||||
|
|
||||||
searchResultItem {
|
searchResultItem {
|
||||||
id(event.eventId)
|
id(eventAndSender.event.eventId)
|
||||||
avatarRenderer(avatarRenderer)
|
avatarRenderer(avatarRenderer)
|
||||||
dateFormatter(dateFormatter)
|
dateFormatter(dateFormatter)
|
||||||
event(event)
|
event(eventAndSender.event)
|
||||||
// I think we should use the data returned by the server?
|
sender(eventAndSender.sender
|
||||||
sender(event.senderId?.let { session.getUser(it) })
|
?: eventAndSender.event.senderId?.let { session.getUser(it) }?.toMatrixItem())
|
||||||
listener { listener?.onItemClicked(event) }
|
listener { listener?.onItemClicked(eventAndSender.event) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,10 @@ import im.vector.app.core.epoxy.ClickListener
|
|||||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.app.core.epoxy.onClick
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
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.MatrixItem
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_search_result)
|
@EpoxyModelClass(layout = R.layout.item_search_result)
|
||||||
abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
|
abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
|
||||||
@ -38,15 +38,15 @@ abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
|
|||||||
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
||||||
@EpoxyAttribute var dateFormatter: VectorDateFormatter? = null
|
@EpoxyAttribute var dateFormatter: VectorDateFormatter? = null
|
||||||
@EpoxyAttribute lateinit var event: Event
|
@EpoxyAttribute lateinit var event: Event
|
||||||
@EpoxyAttribute var sender: User? = null
|
@EpoxyAttribute var sender: MatrixItem? = null
|
||||||
@EpoxyAttribute var listener: ClickListener? = null
|
@EpoxyAttribute var listener: ClickListener? = null
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
|
|
||||||
holder.view.onClick(listener)
|
holder.view.onClick(listener)
|
||||||
sender?.toMatrixItem()?.let { avatarRenderer.render(it, holder.avatarImageView) }
|
sender?.let { avatarRenderer.render(it, holder.avatarImageView) }
|
||||||
holder.memberNameView.text = sender?.getBestName()
|
holder.memberNameView.setTextOrHide(sender?.getBestName())
|
||||||
holder.timeView.text = dateFormatter?.format(event.originServerTs, DateFormatKind.MESSAGE_SIMPLE)
|
holder.timeView.text = dateFormatter?.format(event.originServerTs, DateFormatKind.MESSAGE_SIMPLE)
|
||||||
// TODO Improve that (use formattedBody, etc.)
|
// TODO Improve that (use formattedBody, etc.)
|
||||||
holder.contentView.text = event.content?.get("body") as? String
|
holder.contentView.text = event.content?.get("body") as? String
|
||||||
|
@ -69,9 +69,14 @@ class SearchViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSearchWith(action: SearchAction.SearchWith) {
|
private fun handleSearchWith(action: SearchAction.SearchWith) {
|
||||||
if (action.searchTerm.length > 1) {
|
if (action.searchTerm.isNotEmpty()) {
|
||||||
setState {
|
setState {
|
||||||
copy(searchTerm = action.searchTerm)
|
copy(
|
||||||
|
searchResult = emptyList(),
|
||||||
|
hasMoreResult = false,
|
||||||
|
lastBatchSize = 0,
|
||||||
|
searchTerm = action.searchTerm
|
||||||
|
)
|
||||||
}
|
}
|
||||||
startSearching(false)
|
startSearching(false)
|
||||||
}
|
}
|
||||||
@ -100,9 +105,7 @@ class SearchViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.asyncSearchRequest is Loading) {
|
currentTask?.cancel()
|
||||||
currentTask?.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
@ -118,24 +121,22 @@ class SearchViewModel @AssistedInject constructor(
|
|||||||
callback = it
|
callback = it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onSearchResultSuccess(result, isNextBatch)
|
onSearchResultSuccess(result)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
if (failure is Failure.Cancelled) return@launch
|
if (failure is Failure.Cancelled) return@launch
|
||||||
|
|
||||||
_viewEvents.post(SearchViewEvents.Failure(failure))
|
_viewEvents.post(SearchViewEvents.Failure(failure))
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncSearchRequest = Fail(failure),
|
asyncSearchRequest = Fail(failure)
|
||||||
searchResult = null
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSearchResultSuccess(searchResult: SearchResult, isNextBatch: Boolean) = withState { state ->
|
private fun onSearchResultSuccess(searchResult: SearchResult) = withState { state ->
|
||||||
// Accumulate results if it is the next batch
|
val accumulatedResult = searchResult.results.orEmpty().plus(state.searchResult)
|
||||||
val accumulatedResult = searchResult.results.orEmpty().plus(state.searchResult?.takeIf { isNextBatch }.orEmpty())
|
|
||||||
|
|
||||||
// Note: We do not care about the highlights for the moment, but it will be the same algorithm
|
// 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(
|
copy(
|
||||||
searchResult = accumulatedResult,
|
searchResult = accumulatedResult,
|
||||||
hasMoreResult = !nextBatch.isNullOrEmpty(),
|
hasMoreResult = !nextBatch.isNullOrEmpty(),
|
||||||
lastBatch = searchResult.results,
|
lastBatchSize = searchResult.results.orEmpty().size,
|
||||||
asyncSearchRequest = Success(Unit)
|
asyncSearchRequest = Success(Unit)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
currentTask?.cancel()
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,14 @@ package im.vector.app.features.home.room.detail.search
|
|||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
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(
|
data class SearchViewState(
|
||||||
// Accumulated search result
|
// Accumulated search result
|
||||||
val searchResult: List<Event>? = null,
|
val searchResult: List<EventAndSender> = emptyList(),
|
||||||
val hasMoreResult: Boolean = false,
|
val hasMoreResult: Boolean = false,
|
||||||
// Last batch result will help RecyclerView to position itself
|
// Last batch size, will help RecyclerView to position itself
|
||||||
val lastBatch: List<Event>? = null,
|
val lastBatchSize: Int = 0,
|
||||||
val searchTerm: String? = null,
|
val searchTerm: String? = null,
|
||||||
val roomId: String = "",
|
val roomId: String = "",
|
||||||
// Current pagination request
|
// Current pagination request
|
||||||
|
Loading…
Reference in New Issue
Block a user