From 5fcabca87c003089fa6b1d44a8283902d6ccdb25 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 16 Sep 2020 14:08:35 +0300 Subject: [PATCH 01/47] Data classes for request body created. --- .../session/room/search/EventContext.kt | 34 ++++++++++++++++++ .../internal/session/room/search/Filter.kt | 31 ++++++++++++++++ .../sdk/internal/session/room/search/Order.kt | 29 +++++++++++++++ .../session/room/search/RoomEvents.kt | 36 +++++++++++++++++++ .../session/room/search/SearchBody.kt | 27 ++++++++++++++ .../session/room/search/SearchCategories.kt | 28 +++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/EventContext.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Filter.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Order.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/RoomEvents.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchBody.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchCategories.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/EventContext.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/EventContext.kt new file mode 100644 index 0000000000..36de3e30a8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/EventContext.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class EventContext( + // How many events before the result are returned. + @Json(name = "before_limit") + val beforeLimit: Int? = null, + // How many events after the result are returned. + @Json(name = "after_limit") + val afterLimit: Int? = null, + // Requests that the server returns the historic profile information + @Json(name = "include_profile") + val includeProfile: Boolean? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Filter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Filter.kt new file mode 100644 index 0000000000..717957fa00 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Filter.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class Filter( + // The maximum number of events to return. + @Json(name = "limit") + val limit: Int? = null, + // A list of room IDs to include. If this list is absent then all rooms are included. + @Json(name = "rooms") + val rooms: List? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Order.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Order.kt new file mode 100644 index 0000000000..05a8fe6d3b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Order.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import com.squareup.moshi.JsonClass + +/** + * Represents the order in which to search for results. + */ +@JsonClass(generateAdapter = false) +enum class Order(val value: String) { + RANK("rank"), + RECENT("recent") +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/RoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/RoomEvents.kt new file mode 100644 index 0000000000..83cc91e098 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/RoomEvents.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class RoomEvents( + // Required. The string to search events for. + @Json(name = "search_term") + val searchTerm: String, + @Json(name = "filter") + val filter: Filter? = null, + // By default, this is "rank". One of: ["recent", "rank"] + @Json(name = "order_by") + val orderBy: Order? = null, + // Configures whether any context for the events returned are included in the response. + @Json(name = "event_context") + val eventContext: EventContext? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchBody.kt new file mode 100644 index 0000000000..08d4c0bec8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchBody.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class SearchBody( + @Json(name = "search_categories") + val searchCategories: SearchCategories +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchCategories.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchCategories.kt new file mode 100644 index 0000000000..cfc887ca40 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchCategories.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class SearchCategories( + // Mapping of category name to search criteria. + @Json(name = "room_events") + val roomEvents: RoomEvents? = null +) From 04b41fce3020196cfe9f2ddecb265f6e7639cb04 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 16 Sep 2020 16:04:12 +0300 Subject: [PATCH 02/47] Data classes for the search response created. --- .../sdk/internal/session/room/RoomAPI.kt | 3 ++ .../SearchRequestBody.kt} | 6 +-- .../SearchRequestCategories.kt} | 6 +-- .../SearchRequestEventContext.kt} | 4 +- .../SearchRequestFilter.kt} | 4 +- .../SearchRequestOrder.kt} | 4 +- .../SearchRequestRoomEvents.kt} | 10 ++--- .../room/search/response/SearchResponse.kt | 28 +++++++++++++ .../response/SearchResponseCategories.kt | 27 ++++++++++++ .../response/SearchResponseEventContext.kt | 42 +++++++++++++++++++ .../search/response/SearchResponseItem.kt | 32 ++++++++++++++ .../response/SearchResponseRoomEvents.kt | 33 +++++++++++++++ 12 files changed, 182 insertions(+), 17 deletions(-) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/{SearchBody.kt => request/SearchRequestBody.kt} (84%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/{SearchCategories.kt => request/SearchRequestCategories.kt} (84%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/{EventContext.kt => request/SearchRequestEventContext.kt} (91%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/{Filter.kt => request/SearchRequestFilter.kt} (91%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/{Order.kt => request/SearchRequestOrder.kt} (87%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/{RoomEvents.kt => request/SearchRequestRoomEvents.kt} (81%) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponse.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseCategories.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseEventContext.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseItem.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 35c20cf5cb..ab33249e30 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -365,4 +365,7 @@ internal interface RoomAPI { fun deleteTag(@Path("userId") userId: String, @Path("roomId") roomId: String, @Path("tag") tag: String): Call + + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "search") + fun search() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestBody.kt similarity index 84% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchBody.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestBody.kt index 08d4c0bec8..c174761b08 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestBody.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.room.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchBody( +data class SearchRequestBody( @Json(name = "search_categories") - val searchCategories: SearchCategories + val searchCategories: SearchRequestCategories ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchCategories.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestCategories.kt similarity index 84% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchCategories.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestCategories.kt index cfc887ca40..25e078b608 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchCategories.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestCategories.kt @@ -15,14 +15,14 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.room.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchCategories( +data class SearchRequestCategories( // Mapping of category name to search criteria. @Json(name = "room_events") - val roomEvents: RoomEvents? = null + val roomEvents: SearchRequestRoomEvents? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/EventContext.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestEventContext.kt similarity index 91% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/EventContext.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestEventContext.kt index 36de3e30a8..e74faf85b2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/EventContext.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestEventContext.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.room.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class EventContext( +data class SearchRequestEventContext( // How many events before the result are returned. @Json(name = "before_limit") val beforeLimit: Int? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Filter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestFilter.kt similarity index 91% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Filter.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestFilter.kt index 717957fa00..25b361a2b2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Filter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestFilter.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.room.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class Filter( +data class SearchRequestFilter( // The maximum number of events to return. @Json(name = "limit") val limit: Int? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Order.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestOrder.kt similarity index 87% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Order.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestOrder.kt index 05a8fe6d3b..3fe17c69ae 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/Order.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestOrder.kt @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.room.search.request import com.squareup.moshi.JsonClass @@ -23,7 +23,7 @@ import com.squareup.moshi.JsonClass * Represents the order in which to search for results. */ @JsonClass(generateAdapter = false) -enum class Order(val value: String) { +enum class SearchRequestOrder(val value: String) { RANK("rank"), RECENT("recent") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/RoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestRoomEvents.kt similarity index 81% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/RoomEvents.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestRoomEvents.kt index 83cc91e098..ca2bfdc10e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/RoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestRoomEvents.kt @@ -15,22 +15,22 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.room.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class RoomEvents( +data class SearchRequestRoomEvents( // Required. The string to search events for. @Json(name = "search_term") val searchTerm: String, @Json(name = "filter") - val filter: Filter? = null, + val filter: SearchRequestFilter? = null, // By default, this is "rank". One of: ["recent", "rank"] @Json(name = "order_by") - val orderBy: Order? = null, + val orderBy: SearchRequestOrder? = null, // Configures whether any context for the events returned are included in the response. @Json(name = "event_context") - val eventContext: EventContext? = null + val eventContext: SearchRequestEventContext? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponse.kt new file mode 100644 index 0000000000..78294268bf --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponse.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search.response + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class SearchResponse( + // Required. Describes which categories to search in and their criteria. + @Json(name = "search_categories") + val searchCategories: SearchResponseCategories +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseCategories.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseCategories.kt new file mode 100644 index 0000000000..757c6c5ea8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseCategories.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search.response + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class SearchResponseCategories( + @Json(name = "room_events") + val roomEvents: SearchResponseRoomEvents? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseEventContext.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseEventContext.kt new file mode 100644 index 0000000000..3950fc7bbb --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseEventContext.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search.response + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.util.JsonDict + +@JsonClass(generateAdapter = true) +data class SearchResponseEventContext( + // Events just before the result. + @Json(name = "events_before") + val eventsBefore: List, + // Events just after the result. + @Json(name = "events_after") + val eventsAfter: List, + // Pagination token for the start of the chunk + @Json(name = "start") + val start: String? = null, + // Pagination token for the end of the chunk + @Json(name = "end") + 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 +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseItem.kt new file mode 100644 index 0000000000..248589cf6e --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseItem.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search.response + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.session.events.model.Event + +@JsonClass(generateAdapter = true) +data class SearchResponseItem( + // A number that describes how closely this result matches the search. Higher is closer. + @Json(name = "rank") + val rank: Int? = null, + // The event that matched. + @Json(name = "result") + val event: Event +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt new file mode 100644 index 0000000000..236a93e2c6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search.response + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +class SearchResponseRoomEvents( + // List of results in the requested order. + @Json(name = "results") + val results: List? = null, + @Json(name = "count") + val count: Int? = null, + // List of words which should be highlighted, useful for stemming which may change the query terms. + @Json(name = "highlights") + val highlights: List? = null +) From 051b431f1dd4647f25a101f3471547c8c18ee0f3 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 16 Sep 2020 16:20:57 +0300 Subject: [PATCH 03/47] Search api added to RoomAPI. --- .../matrix/android/sdk/internal/session/room/RoomAPI.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index ab33249e30..c1a06ace1d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -35,6 +35,8 @@ import org.matrix.android.sdk.internal.session.room.membership.joining.InviteBod import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody import org.matrix.android.sdk.internal.session.room.relation.RelationsResponse import org.matrix.android.sdk.internal.session.room.reporting.ReportContentBody +import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestBody +import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse import org.matrix.android.sdk.internal.session.room.send.SendResponse import org.matrix.android.sdk.internal.session.room.tags.TagBody import org.matrix.android.sdk.internal.session.room.timeline.EventContextResponse @@ -366,6 +368,11 @@ internal interface RoomAPI { @Path("roomId") roomId: String, @Path("tag") tag: String): Call + /** + * Performs a full text search across different categories. + */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "search") - fun search() + fun search( + @Query("next_batch") nextBatch: String?, + @Body body: SearchRequestBody): Call } From b521f3656929096d678818a2c44a67dc07f36a1c Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 16 Sep 2020 17:18:47 +0300 Subject: [PATCH 04/47] SearchTask implementation. --- .../sdk/internal/session/room/RoomModule.kt | 5 ++ .../session/room/search/SearchTask.kt | 74 +++++++++++++++++++ .../response/SearchResponseRoomEvents.kt | 5 +- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchTask.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index 700507735b..d3a7cf7df0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -61,6 +61,8 @@ import org.matrix.android.sdk.internal.session.room.relation.FindReactionEventFo import org.matrix.android.sdk.internal.session.room.relation.UpdateQuickReactionTask import org.matrix.android.sdk.internal.session.room.reporting.DefaultReportContentTask import org.matrix.android.sdk.internal.session.room.reporting.ReportContentTask +import org.matrix.android.sdk.internal.session.room.search.DefaultSearchTask +import org.matrix.android.sdk.internal.session.room.search.SearchTask import org.matrix.android.sdk.internal.session.room.state.DefaultSendStateTask import org.matrix.android.sdk.internal.session.room.state.SendStateTask import org.matrix.android.sdk.internal.session.room.tags.AddTagToRoomTask @@ -195,4 +197,7 @@ internal abstract class RoomModule { @Binds abstract fun bindDeleteTagFromRoomTask(task: DefaultDeleteTagFromRoomTask): DeleteTagFromRoomTask + + @Binds + abstract fun bindSearchTask(task: DefaultSearchTask): SearchTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchTask.kt new file mode 100644 index 0000000000..db9e1fc604 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchTask.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.session.room.RoomAPI +import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestBody +import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestCategories +import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestEventContext +import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestFilter +import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestOrder +import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestRoomEvents +import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface SearchTask : Task { + + data class Params( + val searchTerm: String, + val rooms: List, + val nextBatch: String? = null, + val orderByRecent: Boolean, + val limit: Int, + val beforeLimit: Int, + val afterLimit: Int, + val includeProfile: Boolean + ) +} + +internal class DefaultSearchTask @Inject constructor( + private val roomAPI: RoomAPI, + private val eventBus: EventBus +) : SearchTask { + + override suspend fun execute(params: SearchTask.Params): SearchResponse { + return executeRequest(eventBus) { + val searchRequestBody = SearchRequestBody( + searchCategories = SearchRequestCategories( + roomEvents = SearchRequestRoomEvents( + searchTerm = params.searchTerm, + orderBy = if (params.orderByRecent) SearchRequestOrder.RECENT else SearchRequestOrder.RANK, + filter = SearchRequestFilter( + limit = params.limit, + rooms = params.rooms + ), + eventContext = SearchRequestEventContext( + beforeLimit = params.beforeLimit, + afterLimit = params.afterLimit, + includeProfile = params.includeProfile + ) + ) + ) + ) + apiCall = roomAPI.search(params.nextBatch, searchRequestBody) + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt index 236a93e2c6..a14f78ee00 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt @@ -29,5 +29,8 @@ class SearchResponseRoomEvents( val count: Int? = null, // List of words which should be highlighted, useful for stemming which may change the query terms. @Json(name = "highlights") - val highlights: List? = null + val highlights: List? = null, + // Token that can be used to get the next batch of results, by passing as the next_batch parameter to the next call. If this field is absent, there are no more results. + @Json(name = "next_batch") + val nextBatch: String? = null ) From d599cab017d00270a91d128c26c27b5f9f213c14 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 16 Sep 2020 18:38:04 +0300 Subject: [PATCH 05/47] SearchService implementation. --- .../api/session/room/search/SearchService.kt | 49 ++++++++++++++++ .../sdk/internal/session/room/RoomModule.kt | 5 ++ .../room/search/DefaultSearchService.kt | 56 +++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/search/SearchService.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/DefaultSearchService.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/search/SearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/search/SearchService.kt new file mode 100644 index 0000000000..0976ceba18 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/search/SearchService.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.api.session.room.search + +import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.util.Cancelable +import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse + +/** + * This interface defines methods to search messages in rooms. + */ +interface SearchService { + + /** + * Generic function to search a term in multiple rooms. + * Ref: https://matrix.org/docs/spec/client_server/latest#module-search + * @param searchTerm the term to search + * @param rooms roomIds to search term inside + * @param nextBatch the token that retrieved from the previous response. Should be provided to get the next batch of results + * @param limit the maximum number of events to return. + * @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. + */ + fun search(searchTerm: String, + rooms: List, + nextBatch: String?, + orderByRecent: Boolean, + limit: Int, + beforeLimit: Int, + afterLimit: Int, + includeProfile: Boolean, + callback: MatrixCallback): Cancelable +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index d3a7cf7df0..af0abc526a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -25,6 +25,7 @@ import org.commonmark.renderer.html.HtmlRenderer import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.room.RoomDirectoryService import org.matrix.android.sdk.api.session.room.RoomService +import org.matrix.android.sdk.api.session.room.search.SearchService import org.matrix.android.sdk.internal.session.DefaultFileService import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask @@ -61,6 +62,7 @@ import org.matrix.android.sdk.internal.session.room.relation.FindReactionEventFo import org.matrix.android.sdk.internal.session.room.relation.UpdateQuickReactionTask import org.matrix.android.sdk.internal.session.room.reporting.DefaultReportContentTask import org.matrix.android.sdk.internal.session.room.reporting.ReportContentTask +import org.matrix.android.sdk.internal.session.room.search.DefaultSearchService import org.matrix.android.sdk.internal.session.room.search.DefaultSearchTask import org.matrix.android.sdk.internal.session.room.search.SearchTask import org.matrix.android.sdk.internal.session.room.state.DefaultSendStateTask @@ -123,6 +125,9 @@ internal abstract class RoomModule { @Binds abstract fun bindFileService(service: DefaultFileService): FileService + @Binds + abstract fun bindSearchService(service: DefaultSearchService): SearchService + @Binds abstract fun bindCreateRoomTask(task: DefaultCreateRoomTask): CreateRoomTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/DefaultSearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/DefaultSearchService.kt new file mode 100644 index 0000000000..cf57e2a491 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/DefaultSearchService.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.internal.session.room.search + +import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.session.room.search.SearchService +import org.matrix.android.sdk.api.util.Cancelable +import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse +import javax.inject.Inject +import org.matrix.android.sdk.internal.task.TaskExecutor +import org.matrix.android.sdk.internal.task.configureWith + +internal class DefaultSearchService @Inject constructor( + private val taskExecutor: TaskExecutor, + private val searchTask: SearchTask +) : SearchService { + + override fun search(searchTerm: String, + rooms: List, + nextBatch: String?, + orderByRecent: Boolean, + limit: Int, + beforeLimit: Int, + afterLimit: Int, + includeProfile: Boolean, + callback: MatrixCallback): Cancelable { + return searchTask + .configureWith(SearchTask.Params( + searchTerm = searchTerm, + rooms = rooms, + nextBatch = nextBatch, + orderByRecent = orderByRecent, + limit = limit, + beforeLimit = beforeLimit, + afterLimit = afterLimit, + includeProfile = includeProfile + )) { + this.callback = callback + }.executeBy(taskExecutor) + } +} From 05f48255a341274898b3da363146c784665e8695 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 17 Sep 2020 12:02:32 +0300 Subject: [PATCH 06/47] Move search service into session module. --- .../session/{room => }/search/SearchService.kt | 4 ++-- .../sdk/internal/session/SessionModule.kt | 5 +++++ .../android/sdk/internal/session/room/RoomAPI.kt | 4 ++-- .../sdk/internal/session/room/RoomModule.kt | 9 ++------- .../{room => }/search/DefaultSearchService.kt | 6 +++--- .../session/{room => }/search/SearchTask.kt | 16 ++++++++-------- .../search/request/SearchRequestBody.kt | 4 ++-- .../search/request/SearchRequestCategories.kt | 4 ++-- .../search/request/SearchRequestEventContext.kt | 4 ++-- .../search/request/SearchRequestFilter.kt | 4 ++-- .../search/request/SearchRequestOrder.kt | 4 ++-- .../search/request/SearchRequestRoomEvents.kt | 4 ++-- .../{room => }/search/response/SearchResponse.kt | 2 +- .../search/response/SearchResponseCategories.kt | 2 +- .../response/SearchResponseEventContext.kt | 4 ++-- .../search/response/SearchResponseItem.kt | 2 +- .../search/response/SearchResponseRoomEvents.kt | 2 +- 17 files changed, 40 insertions(+), 40 deletions(-) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/{room => }/search/SearchService.kt (93%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/DefaultSearchService.kt (90%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/SearchTask.kt (79%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/request/SearchRequestBody.kt (89%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/request/SearchRequestCategories.kt (89%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/request/SearchRequestEventContext.kt (91%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/request/SearchRequestFilter.kt (90%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/request/SearchRequestOrder.kt (87%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/request/SearchRequestRoomEvents.kt (92%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/response/SearchResponse.kt (93%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/response/SearchResponseCategories.kt (92%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/response/SearchResponseEventContext.kt (93%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/response/SearchResponseItem.kt (94%) rename matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/{room => }/search/response/SearchResponseRoomEvents.kt (95%) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/search/SearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt similarity index 93% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/search/SearchService.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt index 0976ceba18..9a8b2e49e2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/search/SearchService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt @@ -15,11 +15,11 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.session.room.search +package org.matrix.android.sdk.api.session.search import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.util.Cancelable -import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse +import org.matrix.android.sdk.internal.session.search.response.SearchResponse /** * This interface defines methods to search messages in rooms. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index 5397b8d9bd..d615d9e35b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.AccountDataService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.permalinks.PermalinkService +import org.matrix.android.sdk.api.session.search.SearchService import org.matrix.android.sdk.api.session.securestorage.SecureStorageService import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService import org.matrix.android.sdk.api.session.typing.TypingUsersTracker @@ -81,6 +82,7 @@ import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkServic import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor import org.matrix.android.sdk.internal.session.room.create.RoomCreateEventProcessor import org.matrix.android.sdk.internal.session.room.prune.RedactionEventProcessor +import org.matrix.android.sdk.internal.session.search.DefaultSearchService import org.matrix.android.sdk.internal.session.room.tombstone.RoomTombstoneEventProcessor import org.matrix.android.sdk.internal.session.securestorage.DefaultSecureStorageService import org.matrix.android.sdk.internal.session.typing.DefaultTypingUsersTracker @@ -368,4 +370,7 @@ internal abstract class SessionModule { @Binds abstract fun bindTypingUsersTracker(tracker: DefaultTypingUsersTracker): TypingUsersTracker + + @Binds + abstract fun bindSearchService(service: DefaultSearchService): SearchService } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index c1a06ace1d..1a23f3a2f5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -35,8 +35,8 @@ import org.matrix.android.sdk.internal.session.room.membership.joining.InviteBod import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody import org.matrix.android.sdk.internal.session.room.relation.RelationsResponse import org.matrix.android.sdk.internal.session.room.reporting.ReportContentBody -import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestBody -import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse +import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody +import org.matrix.android.sdk.internal.session.search.response.SearchResponse import org.matrix.android.sdk.internal.session.room.send.SendResponse import org.matrix.android.sdk.internal.session.room.tags.TagBody import org.matrix.android.sdk.internal.session.room.timeline.EventContextResponse diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index af0abc526a..77f8f38410 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -25,7 +25,6 @@ import org.commonmark.renderer.html.HtmlRenderer import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.room.RoomDirectoryService import org.matrix.android.sdk.api.session.room.RoomService -import org.matrix.android.sdk.api.session.room.search.SearchService import org.matrix.android.sdk.internal.session.DefaultFileService import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask @@ -62,9 +61,8 @@ import org.matrix.android.sdk.internal.session.room.relation.FindReactionEventFo import org.matrix.android.sdk.internal.session.room.relation.UpdateQuickReactionTask import org.matrix.android.sdk.internal.session.room.reporting.DefaultReportContentTask import org.matrix.android.sdk.internal.session.room.reporting.ReportContentTask -import org.matrix.android.sdk.internal.session.room.search.DefaultSearchService -import org.matrix.android.sdk.internal.session.room.search.DefaultSearchTask -import org.matrix.android.sdk.internal.session.room.search.SearchTask +import org.matrix.android.sdk.internal.session.search.DefaultSearchTask +import org.matrix.android.sdk.internal.session.search.SearchTask import org.matrix.android.sdk.internal.session.room.state.DefaultSendStateTask import org.matrix.android.sdk.internal.session.room.state.SendStateTask import org.matrix.android.sdk.internal.session.room.tags.AddTagToRoomTask @@ -125,9 +123,6 @@ internal abstract class RoomModule { @Binds abstract fun bindFileService(service: DefaultFileService): FileService - @Binds - abstract fun bindSearchService(service: DefaultSearchService): SearchService - @Binds abstract fun bindCreateRoomTask(task: DefaultCreateRoomTask): CreateRoomTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/DefaultSearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt similarity index 90% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/DefaultSearchService.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt index cf57e2a491..1937735191 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/DefaultSearchService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt @@ -15,12 +15,12 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.search import org.matrix.android.sdk.api.MatrixCallback -import org.matrix.android.sdk.api.session.room.search.SearchService +import org.matrix.android.sdk.api.session.search.SearchService import org.matrix.android.sdk.api.util.Cancelable -import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse +import org.matrix.android.sdk.internal.session.search.response.SearchResponse import javax.inject.Inject import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt similarity index 79% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchTask.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt index db9e1fc604..38e87a1251 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/SearchTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt @@ -15,18 +15,18 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search +package org.matrix.android.sdk.internal.session.search import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI -import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestBody -import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestCategories -import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestEventContext -import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestFilter -import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestOrder -import org.matrix.android.sdk.internal.session.room.search.request.SearchRequestRoomEvents -import org.matrix.android.sdk.internal.session.room.search.response.SearchResponse +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.SearchRequestEventContext +import org.matrix.android.sdk.internal.session.search.request.SearchRequestFilter +import org.matrix.android.sdk.internal.session.search.request.SearchRequestOrder +import org.matrix.android.sdk.internal.session.search.request.SearchRequestRoomEvents +import org.matrix.android.sdk.internal.session.search.response.SearchResponse import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestBody.kt similarity index 89% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestBody.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestBody.kt index c174761b08..000f89e751 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestBody.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.request +package org.matrix.android.sdk.internal.session.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchRequestBody( +internal data class SearchRequestBody( @Json(name = "search_categories") val searchCategories: SearchRequestCategories ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestCategories.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestCategories.kt similarity index 89% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestCategories.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestCategories.kt index 25e078b608..606b7320e5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestCategories.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestCategories.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.request +package org.matrix.android.sdk.internal.session.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchRequestCategories( +internal data class SearchRequestCategories( // Mapping of category name to search criteria. @Json(name = "room_events") val roomEvents: SearchRequestRoomEvents? = null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestEventContext.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestEventContext.kt similarity index 91% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestEventContext.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestEventContext.kt index e74faf85b2..9db97295dc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestEventContext.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestEventContext.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.request +package org.matrix.android.sdk.internal.session.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchRequestEventContext( +internal data class SearchRequestEventContext( // How many events before the result are returned. @Json(name = "before_limit") val beforeLimit: Int? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestFilter.kt similarity index 90% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestFilter.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestFilter.kt index 25b361a2b2..196d49346c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestFilter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestFilter.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.request +package org.matrix.android.sdk.internal.session.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchRequestFilter( +internal data class SearchRequestFilter( // The maximum number of events to return. @Json(name = "limit") val limit: Int? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestOrder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestOrder.kt similarity index 87% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestOrder.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestOrder.kt index 3fe17c69ae..eac51ad2df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestOrder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestOrder.kt @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.request +package org.matrix.android.sdk.internal.session.search.request import com.squareup.moshi.JsonClass @@ -23,7 +23,7 @@ import com.squareup.moshi.JsonClass * Represents the order in which to search for results. */ @JsonClass(generateAdapter = false) -enum class SearchRequestOrder(val value: String) { +internal enum class SearchRequestOrder(val value: String) { RANK("rank"), RECENT("recent") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt similarity index 92% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestRoomEvents.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt index ca2bfdc10e..fef1baa990 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/request/SearchRequestRoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.request +package org.matrix.android.sdk.internal.session.search.request import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchRequestRoomEvents( +internal data class SearchRequestRoomEvents( // Required. The string to search events for. @Json(name = "search_term") val searchTerm: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponse.kt similarity index 93% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponse.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponse.kt index 78294268bf..b7debb6b1e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponse.kt @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.response +package org.matrix.android.sdk.internal.session.search.response import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseCategories.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseCategories.kt similarity index 92% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseCategories.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseCategories.kt index 757c6c5ea8..c931b23826 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseCategories.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseCategories.kt @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.response +package org.matrix.android.sdk.internal.session.search.response import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseEventContext.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseEventContext.kt similarity index 93% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseEventContext.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseEventContext.kt index 3950fc7bbb..596645c355 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseEventContext.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseEventContext.kt @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.response +package org.matrix.android.sdk.internal.session.search.response import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.util.JsonDict @JsonClass(generateAdapter = true) -data class SearchResponseEventContext( +internal data class SearchResponseEventContext( // Events just before the result. @Json(name = "events_before") val eventsBefore: List, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseItem.kt similarity index 94% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseItem.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseItem.kt index 248589cf6e..6c284b61c7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseItem.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseItem.kt @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.response +package org.matrix.android.sdk.internal.session.search.response import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt similarity index 95% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt index a14f78ee00..61ed2bf3cf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/search/response/SearchResponseRoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.room.search.response +package org.matrix.android.sdk.internal.session.search.response import com.squareup.moshi.Json import com.squareup.moshi.JsonClass From 2eb60213b461ac4b256b78bf8e8d4d05862efb22 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 17 Sep 2020 12:25:07 +0300 Subject: [PATCH 07/47] Do not support searching in multiple rooms for now. --- .../matrix/android/sdk/api/session/search/SearchService.kt | 4 ++-- .../sdk/internal/session/search/DefaultSearchService.kt | 4 ++-- .../matrix/android/sdk/internal/session/search/SearchTask.kt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) 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 9a8b2e49e2..68fc4e5d6f 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 @@ -30,7 +30,7 @@ interface SearchService { * Generic function to search a term in multiple rooms. * Ref: https://matrix.org/docs/spec/client_server/latest#module-search * @param searchTerm the term to search - * @param rooms roomIds to search term inside + * @param roomId the roomId to search term inside * @param nextBatch the token that retrieved from the previous response. Should be provided to get the next batch of results * @param limit the maximum number of events to return. * @param beforeLimit how many events before the result are returned. @@ -38,7 +38,7 @@ interface SearchService { * @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned. */ fun search(searchTerm: String, - rooms: List, + roomId: String, nextBatch: String?, orderByRecent: Boolean, limit: Int, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt index 1937735191..1f158ec41b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt @@ -31,7 +31,7 @@ internal class DefaultSearchService @Inject constructor( ) : SearchService { override fun search(searchTerm: String, - rooms: List, + roomId: String, nextBatch: String?, orderByRecent: Boolean, limit: Int, @@ -42,7 +42,7 @@ internal class DefaultSearchService @Inject constructor( return searchTask .configureWith(SearchTask.Params( searchTerm = searchTerm, - rooms = rooms, + roomId = roomId, nextBatch = nextBatch, orderByRecent = orderByRecent, limit = limit, 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 38e87a1251..52b4805e02 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 @@ -34,7 +34,7 @@ internal interface SearchTask : Task { data class Params( val searchTerm: String, - val rooms: List, + val roomId: String, val nextBatch: String? = null, val orderByRecent: Boolean, val limit: Int, @@ -58,7 +58,7 @@ internal class DefaultSearchTask @Inject constructor( orderBy = if (params.orderByRecent) SearchRequestOrder.RECENT else SearchRequestOrder.RANK, filter = SearchRequestFilter( limit = params.limit, - rooms = params.rooms + rooms = listOf(params.roomId) ), eventContext = SearchRequestEventContext( beforeLimit = params.beforeLimit, From c46f0a7430bd1391e08df762613ad84de635b856 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 17 Sep 2020 16:08:46 +0300 Subject: [PATCH 08/47] Simple integration test implementation for searching messages in a room. --- .../sdk/session/search/SearchMessagesTest.kt | 114 ++++++++++++++++++ .../src/main/AndroidManifest.xml | 10 ++ 2 files changed, 124 insertions(+) create mode 100644 matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt new file mode 100644 index 0000000000..3e2960af43 --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt @@ -0,0 +1,114 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.session.search + +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.message.MessageContent +import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings +import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.TestConstants +import org.matrix.android.sdk.internal.session.search.response.SearchResponse +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +@RunWith(JUnit4::class) +@FixMethodOrder(MethodSorters.JVM) +class SearchMessagesTest : InstrumentedTest { + + private val MESSAGE = "Lorem ipsum dolor sit amet" + + private val commonTestHelper = CommonTestHelper(context()) + private val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + + @Test + fun sendTextMessageAndSearchPartOfIt() { + val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false) + val aliceSession = cryptoTestData.firstSession + val aliceRoomId = cryptoTestData.roomId + aliceSession.cryptoService().setWarnOnUnknownDevices(false) + val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!! + val aliceTimeline = roomFromAlicePOV.createTimeline(null, TimelineSettings(10)) + aliceTimeline.start() + + commonTestHelper.sendTextMessage( + roomFromAlicePOV, + MESSAGE, + 2) + + run { + var lock = CountDownLatch(1) + + val eventListener = commonTestHelper.createEventListener(lock) { snapshot -> + snapshot.count { it.root.content.toModel()?.body?.startsWith(MESSAGE).orFalse() } == 2 + } + + aliceTimeline.addListener(eventListener) + commonTestHelper.await(lock) + + lock = CountDownLatch(1) + aliceSession + .searchService() + .search( + searchTerm = "lore", + limit = 10, + includeProfile = true, + afterLimit = 0, + beforeLimit = 10, + orderByRecent = true, + nextBatch = null, + roomId = aliceRoomId, + callback = object : MatrixCallback { + override fun onSuccess(data: SearchResponse) { + super.onSuccess(data) + assertTrue(data.searchCategories.roomEvents?.results?.size == 2) + assertTrue( + data.searchCategories.roomEvents?.results + ?.all { + (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() + }.orFalse() + ) + lock.countDown() + } + + override fun onFailure(failure: Throwable) { + super.onFailure(failure) + fail(failure.localizedMessage) + lock.countDown() + } + } + ) + lock.await(TestConstants.timeOutMillis, TimeUnit.MILLISECONDS) + + aliceTimeline.removeAllListeners() + cryptoTestData.cleanUp(commonTestHelper) + } + + aliceSession.startSync(true) +} +} diff --git a/matrix-sdk-android/src/main/AndroidManifest.xml b/matrix-sdk-android/src/main/AndroidManifest.xml index 52238f824c..eeb944d955 100644 --- a/matrix-sdk-android/src/main/AndroidManifest.xml +++ b/matrix-sdk-android/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ @@ -7,6 +8,15 @@ + + + diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index 86d59b630b..014a244bf8 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -52,6 +52,7 @@ import im.vector.app.features.home.HomeDrawerFragment import im.vector.app.features.home.LoadingFragment import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment import im.vector.app.features.home.room.detail.RoomDetailFragment +import im.vector.app.features.home.room.detail.search.SearchFragment import im.vector.app.features.home.room.list.RoomListFragment import im.vector.app.features.login.LoginCaptchaFragment import im.vector.app.features.login.LoginFragment @@ -570,4 +571,9 @@ interface FragmentModule { @IntoMap @FragmentKey(RoomBannedMemberListFragment::class) fun bindRoomBannedMemberListFragment(fragment: RoomBannedMemberListFragment): Fragment + + @Binds + @IntoMap + @FragmentKey(SearchFragment::class) + fun bindSearchFragment(fragment: SearchFragment): Fragment } diff --git a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt index d337ec7977..17ec00952b 100644 --- a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt +++ b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt @@ -38,6 +38,7 @@ import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.HomeModule import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet +import im.vector.app.features.home.room.detail.search.SearchActivity import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet @@ -142,6 +143,7 @@ interface ScreenComponent { fun inject(activity: VectorCallActivity) fun inject(activity: VectorAttachmentViewerActivity) fun inject(activity: VectorJitsiActivity) + fun inject(activity: SearchActivity) /* ========================================================================================== * BottomSheets diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 3b4795b965..34aa6a0831 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -673,6 +673,10 @@ class RoomDetailFragment @Inject constructor( roomDetailViewModel.handle(RoomDetailAction.EndCall) true } + R.id.search -> { + navigator.openSearch(requireContext(), roomDetailArgs.roomId) + true + } else -> super.onOptionsItemSelected(item) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt new file mode 100644 index 0000000000..2774ef4d8e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class SearchAction : VectorViewModelAction 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 new file mode 100644 index 0000000000..bedc4cb881 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import android.content.Context +import android.content.Intent +import com.airbnb.mvrx.MvRx +import im.vector.app.R +import im.vector.app.core.di.ScreenComponent +import im.vector.app.core.extensions.addFragment +import im.vector.app.core.platform.VectorBaseActivity + +class SearchActivity : VectorBaseActivity() { + + override fun getLayoutRes() = R.layout.activity_simple + + override fun injectWith(injector: ScreenComponent) { + super.injectWith(injector) + injector.inject(this) + } + + override fun initUiAndData() { + if (isFirstCreation()) { + val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return + addFragment(R.id.simpleFragmentContainer, SearchFragment::class.java, fragmentArgs) + } + } + + companion object { + fun newIntent(context: Context, args: SearchArgs): Intent { + return Intent(context, SearchActivity::class.java).apply { + 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 new file mode 100644 index 0000000000..f5b8440b58 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import android.os.Bundle +import android.os.Parcelable +import android.view.View +import com.airbnb.mvrx.args +import com.airbnb.mvrx.fragmentViewModel +import im.vector.app.R +import im.vector.app.core.platform.VectorBaseFragment +import kotlinx.android.parcel.Parcelize +import javax.inject.Inject + +@Parcelize +data class SearchArgs( + val roomId: String +) : Parcelable + +class SearchFragment @Inject constructor( + val viewModelFactory: SearchViewModel.Factory +) : VectorBaseFragment() { + + private val fragmentArgs: SearchArgs by args() + private val searchViewModel: SearchViewModel by fragmentViewModel() + + override fun getLayoutResId() = R.layout.fragment_search + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt new file mode 100644 index 0000000000..a5489e9240 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import im.vector.app.core.platform.VectorViewEvents + +sealed class SearchViewEvents : VectorViewEvents 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 new file mode 100644 index 0000000000..de75c0dd20 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.platform.VectorViewModel + +class SearchViewModel @AssistedInject constructor( + @Assisted private val initialState: SearchViewState +) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: SearchViewState): SearchViewModel + } + + companion object : MvRxViewModelFactory { + + @JvmStatic + override fun create(viewModelContext: ViewModelContext, state: SearchViewState): SearchViewModel? { + val fragment: SearchFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.viewModelFactory.create(state) + } + } + + override fun handle(action: SearchAction) { + } +} 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 new file mode 100644 index 0000000000..785d61dc00 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import com.airbnb.mvrx.MvRxState + +data class SearchViewState( + val searchTerm: String = "" +) : MvRxState diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 3a8d302fc7..5ad600dfff 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -43,6 +43,8 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheet import im.vector.app.features.debug.DebugMenuActivity import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.RoomDetailArgs +import im.vector.app.features.home.room.detail.search.SearchActivity +import im.vector.app.features.home.room.detail.search.SearchArgs import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes import im.vector.app.features.home.room.filtered.FilteredRoomsActivity import im.vector.app.features.invite.InviteUsersToRoomActivity @@ -329,6 +331,11 @@ class DefaultNavigator @Inject constructor( } } + override fun openSearch(context: Context, roomId: String) { + val intent = SearchActivity.newIntent(context, SearchArgs(roomId)) + context.startActivity(intent) + } + private fun startActivity(context: Context, intent: Intent, buildTask: Boolean) { if (buildTask) { val stackBuilder = TaskStackBuilder.create(context) diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt index e92fea267f..b2efb1e931 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt @@ -109,4 +109,6 @@ interface Navigator { view: View, inMemory: List = emptyList(), options: ((MutableList>) -> Unit)?) + + fun openSearch(context: Context, roomId: String) } diff --git a/vector/src/main/res/layout/fragment_search.xml b/vector/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000000..77d9ef65f8 --- /dev/null +++ b/vector/src/main/res/layout/fragment_search.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file From 86b46d14426ec806dad0a29b4ae0388af558cc31 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 21 Sep 2020 17:01:27 +0300 Subject: [PATCH 14/47] Configure SearchView as activity toolbar. --- .../home/room/detail/search/SearchActivity.kt | 31 ++++++++++++- .../home/room/detail/search/SearchFragment.kt | 5 +++ .../src/main/res/layout/activity_search.xml | 43 +++++++++++++++++++ .../src/main/res/layout/fragment_search.xml | 3 ++ 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 vector/src/main/res/layout/activity_search.xml 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 bedc4cb881..70205eed62 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 @@ -18,29 +18,56 @@ package im.vector.app.features.home.room.detail.search import android.content.Context import android.content.Intent +import android.os.Bundle +import androidx.appcompat.widget.SearchView import com.airbnb.mvrx.MvRx import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity +import kotlinx.android.synthetic.main.activity_search.* class SearchActivity : VectorBaseActivity() { - override fun getLayoutRes() = R.layout.activity_simple + private val searchFragment: SearchFragment? + get() { + return supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as? SearchFragment + } + + override fun getLayoutRes() = R.layout.activity_search override fun injectWith(injector: ScreenComponent) { super.injectWith(injector) injector.inject(this) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + configureToolbar(searchToolbar) + } + override fun initUiAndData() { if (isFirstCreation()) { val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return - addFragment(R.id.simpleFragmentContainer, SearchFragment::class.java, fragmentArgs) + addFragment(R.id.searchFragmentContainer, SearchFragment::class.java, fragmentArgs, FRAGMENT_TAG) } + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + searchFragment?.search(query) + return true + } + + override fun onQueryTextChange(newText: String): Boolean { + return true + } + }) + // Open the keyboard immediately + searchView.requestFocus() } companion object { + private const val FRAGMENT_TAG = "SearchFragment" + fun newIntent(context: Context, args: SearchArgs): Intent { return Intent(context, SearchActivity::class.java).apply { 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 f5b8440b58..0a0604eb38 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 @@ -24,6 +24,7 @@ import com.airbnb.mvrx.fragmentViewModel import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import kotlinx.android.parcel.Parcelize +import timber.log.Timber import javax.inject.Inject @Parcelize @@ -43,4 +44,8 @@ class SearchFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) } + + fun search(query: String) { + Timber.d(query) + } } diff --git a/vector/src/main/res/layout/activity_search.xml b/vector/src/main/res/layout/activity_search.xml new file mode 100644 index 0000000000..a3aa21eecc --- /dev/null +++ b/vector/src/main/res/layout/activity_search.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_search.xml b/vector/src/main/res/layout/fragment_search.xml index 77d9ef65f8..2916089675 100644 --- a/vector/src/main/res/layout/fragment_search.xml +++ b/vector/src/main/res/layout/fragment_search.xml @@ -1,6 +1,9 @@ + + \ No newline at end of file From 8759bcca84c69e8aab5e7aa365ba37922ae05f32 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 24 Sep 2020 10:14:36 +0300 Subject: [PATCH 15/47] Map api response to a domain object. --- .../sdk/session/search/SearchMessagesTest.kt | 22 ++++++------- .../android/sdk/api/session/room/Room.kt | 4 +-- .../sdk/api/session/search/SearchResult.kt | 32 +++++++++++++++++++ .../sdk/api/session/search/SearchService.kt | 3 +- .../sdk/internal/session/room/DefaultRoom.kt | 4 +-- .../sdk/internal/session/room/RoomAPI.kt | 2 +- .../session/search/DefaultSearchService.kt | 4 +-- .../sdk/internal/session/search/SearchTask.kt | 17 +++++++--- 8 files changed, 64 insertions(+), 24 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchResult.kt diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt index b7d253ca00..1d4eb758ed 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt @@ -30,10 +30,10 @@ import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings +import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.TestConstants -import org.matrix.android.sdk.internal.session.search.response.SearchResponse import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit @@ -83,14 +83,14 @@ class SearchMessagesTest : InstrumentedTest { orderByRecent = true, nextBatch = null, roomId = aliceRoomId, - callback = object : MatrixCallback { - override fun onSuccess(data: SearchResponse) { + callback = object : MatrixCallback { + override fun onSuccess(data: SearchResult) { super.onSuccess(data) - assertTrue(data.searchCategories.roomEvents?.results?.size == 2) + assertTrue(data.results?.size == 2) assertTrue( - data.searchCategories.roomEvents?.results + data.results ?.all { - (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() + (it.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() }.orFalse() ) lock.countDown() @@ -147,14 +147,14 @@ class SearchMessagesTest : InstrumentedTest { beforeLimit = 10, orderByRecent = true, nextBatch = null, - callback = object : MatrixCallback { - override fun onSuccess(data: SearchResponse) { + callback = object : MatrixCallback { + override fun onSuccess(data: SearchResult) { super.onSuccess(data) - assertTrue(data.searchCategories.roomEvents?.results?.size == 2) + assertTrue(data.results?.size == 2) assertTrue( - data.searchCategories.roomEvents?.results + data.results ?.all { - (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() + (it.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() }.orFalse() ) lock.countDown() 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 d09a42753b..a27cdad551 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 @@ -34,9 +34,9 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService +import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.Optional -import org.matrix.android.sdk.internal.session.search.response.SearchResponse /** * This interface defines methods to interact within a room. @@ -90,5 +90,5 @@ interface Room : beforeLimit: Int, afterLimit: Int, includeProfile: Boolean, - callback: MatrixCallback): Cancelable + callback: MatrixCallback): Cancelable } 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 new file mode 100644 index 0000000000..4529bf6d13 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchResult.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2020 New Vector Ltd + * 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.api.session.search + +import org.matrix.android.sdk.api.session.events.model.Event + +/** + * Domain class to represent the response of a search request in a room. + */ +data class SearchResult( + // Token that can be used to get the next batch of results, by passing as the next_batch parameter to the next call. If this field is absent, there are no more results. + val nextBatch: String? = null, + // List of words which should be highlighted, useful for stemming which may change the query terms. + var highlights: List? = null, + // List of results in the requested order. + var results: List? = null +) 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 2087af6a81..b089a597e3 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 @@ -19,7 +19,6 @@ package org.matrix.android.sdk.api.session.search import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.util.Cancelable -import org.matrix.android.sdk.internal.session.search.response.SearchResponse /** * This interface defines methods to search messages in rooms. @@ -45,5 +44,5 @@ interface SearchService { beforeLimit: Int, afterLimit: Int, includeProfile: Boolean, - callback: MatrixCallback): Cancelable + callback: MatrixCallback): Cancelable } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt index 33fa98f8ce..0eb64af8a0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt @@ -36,13 +36,13 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService +import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.session.room.state.SendStateTask import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource import org.matrix.android.sdk.internal.session.search.SearchTask -import org.matrix.android.sdk.internal.session.search.response.SearchResponse import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith import java.security.InvalidParameterException @@ -135,7 +135,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String, beforeLimit: Int, afterLimit: Int, includeProfile: Boolean, - callback: MatrixCallback): Cancelable { + callback: MatrixCallback): Cancelable { return searchTask .configureWith(SearchTask.Params( searchTerm = searchTerm, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 1a23f3a2f5..db99adbafb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -36,12 +36,12 @@ import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePid import org.matrix.android.sdk.internal.session.room.relation.RelationsResponse import org.matrix.android.sdk.internal.session.room.reporting.ReportContentBody import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody -import org.matrix.android.sdk.internal.session.search.response.SearchResponse import org.matrix.android.sdk.internal.session.room.send.SendResponse import org.matrix.android.sdk.internal.session.room.tags.TagBody import org.matrix.android.sdk.internal.session.room.timeline.EventContextResponse import org.matrix.android.sdk.internal.session.room.timeline.PaginationResponse import org.matrix.android.sdk.internal.session.room.typing.TypingBody +import org.matrix.android.sdk.internal.session.search.response.SearchResponse import retrofit2.Call import retrofit2.http.Body import retrofit2.http.DELETE diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt index 1f158ec41b..0b380f4d35 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.search import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.session.search.SearchService import org.matrix.android.sdk.api.util.Cancelable -import org.matrix.android.sdk.internal.session.search.response.SearchResponse import javax.inject.Inject import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith @@ -38,7 +38,7 @@ internal class DefaultSearchService @Inject constructor( beforeLimit: Int, afterLimit: Int, includeProfile: Boolean, - callback: MatrixCallback): Cancelable { + callback: MatrixCallback): Cancelable { return searchTask .configureWith(SearchTask.Params( searchTerm = searchTerm, 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 17f980bb77..4502d2a60a 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,6 +18,7 @@ package org.matrix.android.sdk.internal.session.search import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody @@ -30,7 +31,7 @@ import org.matrix.android.sdk.internal.session.search.response.SearchResponse import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject -internal interface SearchTask : Task { +internal interface SearchTask : Task { data class Params( val searchTerm: String, @@ -49,8 +50,8 @@ internal class DefaultSearchTask @Inject constructor( private val eventBus: EventBus ) : SearchTask { - override suspend fun execute(params: SearchTask.Params): SearchResponse { - return executeRequest(eventBus) { + override suspend fun execute(params: SearchTask.Params): SearchResult { + return executeRequest(eventBus) { val searchRequestBody = SearchRequestBody( searchCategories = SearchRequestCategories( roomEvents = SearchRequestRoomEvents( @@ -69,6 +70,14 @@ internal class DefaultSearchTask @Inject constructor( ) ) apiCall = roomAPI.search(params.nextBatch, searchRequestBody) - } + }.toDomain().apply { results = results?.reversed() } + } + + private fun SearchResponse.toDomain(): SearchResult { + return SearchResult( + nextBatch = searchCategories.roomEvents?.nextBatch, + highlights = searchCategories.roomEvents?.highlights, + results = searchCategories.roomEvents?.results?.map { it.event } + ) } } From d6fcf63230e291f7e0b68a86266d4afd87d54205 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 24 Sep 2020 10:19:26 +0300 Subject: [PATCH 16/47] Implement search result controller and item. --- .../detail/search/SearchResultController.kt | 80 +++++++++++++++++++ .../room/detail/search/SearchResultItem.kt | 63 +++++++++++++++ .../src/main/res/layout/fragment_search.xml | 15 ++-- .../main/res/layout/item_search_result.xml | 60 ++++++++++++++ vector/src/main/res/values/strings.xml | 1 + 5 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt create mode 100644 vector/src/main/res/layout/item_search_result.xml 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 new file mode 100644 index 0000000000..82d3120311 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import com.airbnb.epoxy.TypedEpoxyController +import im.vector.app.core.date.DateFormatKind +import im.vector.app.core.date.VectorDateFormatter +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 java.util.Calendar +import javax.inject.Inject + +class SearchResultController @Inject constructor( + private val session: Session, + private val avatarRenderer: AvatarRenderer, + private val dateFormatter: VectorDateFormatter +) : TypedEpoxyController() { + + var listener: Listener? = null + + interface Listener { + fun onItemClicked(event: Event) + } + + init { + setData(null) + } + + override fun buildModels(data: SearchViewState?) { + data?.searchResult?.results ?: return + + buildSearchResultItems(data.searchResult.results!!) + } + + private fun buildSearchResultItems(events: List) { + var lastDate: Calendar? = null + + events.forEach { event -> + val eventDate = Calendar.getInstance().apply { + timeInMillis = event.originServerTs ?: System.currentTimeMillis() + } + if (lastDate?.get(Calendar.DAY_OF_YEAR) != eventDate.get(Calendar.DAY_OF_YEAR)) { + genericItemHeader { + id(eventDate.hashCode()) + text(dateFormatter.format(eventDate.timeInMillis, DateFormatKind.EDIT_HISTORY_HEADER)) + } + } + lastDate = eventDate + + searchResultItem { + id(event.eventId) + avatarRenderer(avatarRenderer) + dateFormatter(dateFormatter) + event(event) + sender(event.senderId?.let { session.getUser(it) }) + listener(object : SearchResultItem.Listener { + override fun onItemClicked() { + listener?.onItemClicked(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 new file mode 100644 index 0000000000..fb0121cbcf --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2020 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.features.home.room.detail.search + +import android.widget.ImageView +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.date.DateFormatKind +import im.vector.app.core.date.VectorDateFormatter +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +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 + +@EpoxyModelClass(layout = R.layout.item_search_result) +abstract class SearchResultItem : VectorEpoxyModel() { + + @EpoxyAttribute var avatarRenderer: AvatarRenderer? = null + @EpoxyAttribute var dateFormatter: VectorDateFormatter? = null + @EpoxyAttribute var event: Event? = null + @EpoxyAttribute var sender: User? = null + @EpoxyAttribute var listener: Listener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + event ?: return + + holder.view.setOnClickListener { listener?.onItemClicked() } + sender?.toMatrixItem()?.let { avatarRenderer?.render(it, holder.avatarImageView) } + holder.memberNameView.text = sender?.displayName + holder.timeView.text = dateFormatter?.format(event!!.originServerTs, DateFormatKind.MESSAGE_SIMPLE) + holder.contentView.text = event?.content?.get("body") as? String + } + + class Holder : VectorEpoxyHolder() { + val avatarImageView by bind(R.id.messageAvatarImageView) + val memberNameView by bind(R.id.messageMemberNameView) + val timeView by bind(R.id.messageTimeView) + val contentView by bind(R.id.messageContentView) + } + + interface Listener { + fun onItemClicked() + } +} diff --git a/vector/src/main/res/layout/fragment_search.xml b/vector/src/main/res/layout/fragment_search.xml index 2916089675..5478e1f68c 100644 --- a/vector/src/main/res/layout/fragment_search.xml +++ b/vector/src/main/res/layout/fragment_search.xml @@ -1,9 +1,14 @@ - + android:layout_height="match_parent" + android:background="?riotx_header_panel_background"> + - - \ No newline at end of file + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_search_result.xml b/vector/src/main/res/layout/item_search_result.xml new file mode 100644 index 0000000000..9946a2fb50 --- /dev/null +++ b/vector/src/main/res/layout/item_search_result.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 0edd930498..ee5b8fecb1 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -628,6 +628,7 @@ MESSAGES PEOPLE FILES + Searching in encrypted rooms is not supported yet. JOIN From 6c6d0dbc3d9f907faf4dc85f3054fc17c4bd7d51 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 24 Sep 2020 10:20:36 +0300 Subject: [PATCH 17/47] Show not supported warning for e2e rooms. --- .../features/home/room/detail/RoomDetailFragment.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 34aa6a0831..51aeda2aab 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -674,13 +674,21 @@ class RoomDetailFragment @Inject constructor( true } R.id.search -> { - navigator.openSearch(requireContext(), roomDetailArgs.roomId) + handleSearchAction() true } else -> super.onOptionsItemSelected(item) } } + private fun handleSearchAction() { + if (session.getRoom(roomDetailArgs.roomId)?.isEncrypted() == false) { + navigator.openSearch(requireContext(), roomDetailArgs.roomId) + } else { + showDialogWithMessage(getString(R.string.search_is_not_supported_in_e2e_room)) + } + } + private fun handleCallRequest(item: MenuItem) = withState(roomDetailViewModel) { state -> val roomSummary = state.asyncRoomSummary.invoke() ?: return@withState val isVideoCall = item.itemId == R.id.video_call From 5e56e7cf829464d429ed06cc2ffe8013bfe10ef8 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 24 Sep 2020 10:21:26 +0300 Subject: [PATCH 18/47] Implement search state, action and view events. --- .../app/features/home/room/detail/search/SearchAction.kt | 6 +++++- .../features/home/room/detail/search/SearchViewEvents.kt | 5 ++++- .../features/home/room/detail/search/SearchViewState.kt | 9 ++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt index 2774ef4d8e..d295784a8c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt @@ -18,4 +18,8 @@ package im.vector.app.features.home.room.detail.search import im.vector.app.core.platform.VectorViewModelAction -sealed class SearchAction : VectorViewModelAction +sealed class SearchAction : VectorViewModelAction { + data class SearchWith(val roomId: String, val searchTerm: String) : SearchAction() + object ScrolledToTop : SearchAction() + object Retry : SearchAction() +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt index a5489e9240..41dabd8686 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt @@ -18,4 +18,7 @@ package im.vector.app.features.home.room.detail.search import im.vector.app.core.platform.VectorViewEvents -sealed class SearchViewEvents : VectorViewEvents +sealed class SearchViewEvents : VectorViewEvents { + data class Failure(val throwable: Throwable) : SearchViewEvents() + data class Loading(val message: CharSequence? = null) : SearchViewEvents() +} 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 785d61dc00..02db098e68 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 @@ -17,7 +17,14 @@ package im.vector.app.features.home.room.detail.search import com.airbnb.mvrx.MvRxState +import org.matrix.android.sdk.api.session.search.SearchResult data class SearchViewState( - val searchTerm: String = "" + // Accumulated search result + val searchResult: SearchResult? = null, + // Last batch result will help RecyclerView to position itself + val lastBatch: SearchResult? = null, + val searchTerm: String? = null, + val roomId: String? = null, + val isNextBatch: Boolean = false ) : MvRxState From 62449ee543bec0593b060f8cb7181385cb67f846 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 24 Sep 2020 10:22:26 +0300 Subject: [PATCH 19/47] Support searching and pagination. --- .../home/room/detail/search/SearchFragment.kt | 95 ++++++++++++++++++- .../room/detail/search/SearchViewModel.kt | 92 +++++++++++++++++- 2 files changed, 182 insertions(+), 5 deletions(-) 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 0a0604eb38..1f8f7fa422 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 @@ -19,12 +19,24 @@ package im.vector.app.features.home.room.detail.search import android.os.Bundle import android.os.Parcelable import android.view.View +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState import im.vector.app.R +import im.vector.app.core.extensions.cleanup +import im.vector.app.core.extensions.configureWith +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.extensions.hideKeyboard +import im.vector.app.core.extensions.trackItemsVisibilityChange +import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.resources.StringProvider import kotlinx.android.parcel.Parcelize -import timber.log.Timber +import kotlinx.android.synthetic.main.fragment_search.* +import org.matrix.android.sdk.api.session.events.model.Event import javax.inject.Inject @Parcelize @@ -33,19 +45,94 @@ data class SearchArgs( ) : Parcelable class SearchFragment @Inject constructor( - val viewModelFactory: SearchViewModel.Factory -) : VectorBaseFragment() { + val viewModelFactory: SearchViewModel.Factory, + val controller: SearchResultController, + val stringProvider: StringProvider +) : VectorBaseFragment(), StateView.EventCallback, SearchResultController.Listener { private val fragmentArgs: SearchArgs by args() private val searchViewModel: SearchViewModel by fragmentViewModel() + private var pendingScrollToPosition: Int? = null + override fun getLayoutResId() = R.layout.fragment_search override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + stateView.contentView = searchResultRecycler + stateView.eventCallback = this + + configureRecyclerView() + + searchViewModel.observeViewEvents { + when (it) { + is SearchViewEvents.Failure -> { + stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(it.throwable)) + } + is SearchViewEvents.Loading -> { + stateView.state = StateView.State.Loading + } + }.exhaustive + } + } + + private fun configureRecyclerView() { + searchResultRecycler.trackItemsVisibilityChange() + searchResultRecycler.configureWith(controller, showDivider = false) + controller.listener = this + + controller.addModelBuildListener { + pendingScrollToPosition?.let { + searchResultRecycler.scrollToPosition(it) + } + } + + searchResultRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + // Load next batch when scrolled to the top + if (newState == RecyclerView.SCROLL_STATE_IDLE + && (searchResultRecycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition() == 0) { + searchViewModel.handle(SearchAction.ScrolledToTop) + } + } + }) + } + + override fun onDestroy() { + super.onDestroy() + searchResultRecycler?.cleanup() + controller.listener = null + } + + override fun invalidate() = withState(searchViewModel) { state -> + if (state.searchResult?.results?.isNotEmpty() == true) { + stateView.state = StateView.State.Content + controller.setData(state) + + val lastBatchSize = state.lastBatch?.results?.size ?: 0 + val scrollPosition = if (lastBatchSize > 0) lastBatchSize - 1 else 0 + pendingScrollToPosition = scrollPosition + } else { + stateView.state = StateView.State.Empty( + title = stringProvider.getString(R.string.search_no_results), + image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search) + ) + } } fun search(query: String) { - Timber.d(query) + view?.hideKeyboard() + searchViewModel.handle(SearchAction.SearchWith(fragmentArgs.roomId, query)) + } + + override fun onRetryClicked() { + searchViewModel.handle(SearchAction.Retry) + } + + override fun onItemClicked(event: Event) { + event.roomId ?: return + + navigator.openRoom(requireContext(), event.roomId!!, event.eventId) } } 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 de75c0dd20..67befc80be 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 @@ -21,10 +21,15 @@ import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel +import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.search.SearchResult class SearchViewModel @AssistedInject constructor( - @Assisted private val initialState: SearchViewState + @Assisted private val initialState: SearchViewState, + private val session: Session ) : VectorViewModel(initialState) { @AssistedInject.Factory @@ -42,5 +47,90 @@ class SearchViewModel @AssistedInject constructor( } override fun handle(action: SearchAction) { + when (action) { + is SearchAction.SearchWith -> handleSearchWith(action) + is SearchAction.ScrolledToTop -> handleScrolledToTop() + is SearchAction.Retry -> handleRetry() + }.exhaustive + } + + private fun handleSearchWith(action: SearchAction.SearchWith) { + if (action.searchTerm.length > 1) { + setState { + copy(searchTerm = action.searchTerm, roomId = action.roomId, isNextBatch = false) + } + + startSearching() + } + } + + private fun handleScrolledToTop() { + setState { + copy(isNextBatch = true) + } + startSearching(true) + } + + private fun handleRetry() { + startSearching() + } + + private fun startSearching(scrolledToTop: Boolean = false) = withState { state -> + if (state.roomId == null || state.searchTerm == null) return@withState + + // There is no batch to retrieve + if (scrolledToTop && state.searchResult?.nextBatch == null) return@withState + + _viewEvents.post(SearchViewEvents.Loading()) + + session + .getRoom(state.roomId) + ?.search( + searchTerm = state.searchTerm, + nextBatch = state.searchResult?.nextBatch, + orderByRecent = true, + beforeLimit = 0, + afterLimit = 0, + includeProfile = true, + limit = 20, + callback = object : MatrixCallback { + override fun onFailure(failure: Throwable) { + onSearchFailure(failure) + } + + override fun onSuccess(data: SearchResult) { + onSearchResultSuccess(data) + } + } + ) + } + + private fun onSearchFailure(failure: Throwable) { + setState { + copy(searchResult = null) + } + _viewEvents.post(SearchViewEvents.Failure(failure)) + } + + private fun onSearchResultSuccess(searchResult: SearchResult) = withState { state -> + val accumulatedResult = SearchResult( + nextBatch = searchResult.nextBatch, + results = searchResult.results, + highlights = searchResult.highlights + ) + + // Accumulate results if it is the next batch + if (state.isNextBatch) { + if (state.searchResult != null) { + accumulatedResult.results = accumulatedResult.results?.plus(state.searchResult.results!!) + } + if (state.searchResult?.highlights != null) { + accumulatedResult.highlights = accumulatedResult.highlights?.plus(state.searchResult.highlights!!) + } + } + + setState { + copy(searchResult = accumulatedResult, lastBatch = searchResult) + } } } From 0df3a8ad986b6c712105d8ae8002017178987e98 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 24 Sep 2020 11:44:17 +0300 Subject: [PATCH 20/47] Changelog added. --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 026d7af6cd..c357515efa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ Changes in Element 1.0.9 (2020-XX-XX) =================================================== Features ✨: + - Search messages in a room - phase 1 (#2110) - Hide encrypted history (before user is invited). Can be shown if wanted in developer settings Improvements 🙌: @@ -18,7 +19,7 @@ Translations 🗣: - SDK API changes ⚠️: - - + - Search messages in a room by using Session.searchService() or Room.search() Build 🧱: - Use Update Gradle Wrapper Action From 70be853acdbda871fee8f05de2303b151c3e1f9e Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 24 Sep 2020 12:21:31 +0300 Subject: [PATCH 21/47] Update no results found icon. --- .../home/room/detail/search/SearchFragment.kt | 2 +- .../res/drawable/ic_search_no_results.xml | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/res/drawable/ic_search_no_results.xml 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 1f8f7fa422..fa60d33e64 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 @@ -116,7 +116,7 @@ class SearchFragment @Inject constructor( } else { stateView.state = StateView.State.Empty( title = stringProvider.getString(R.string.search_no_results), - image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search) + image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search_no_results) ) } } diff --git a/vector/src/main/res/drawable/ic_search_no_results.xml b/vector/src/main/res/drawable/ic_search_no_results.xml new file mode 100644 index 0000000000..24c0f00131 --- /dev/null +++ b/vector/src/main/res/drawable/ic_search_no_results.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file From 430a0d249221f2830135c5b60de26699554ae5cc Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 28 Sep 2020 18:51:30 +0300 Subject: [PATCH 22/47] Create separate search module. --- .../sdk/internal/session/SessionComponent.kt | 4 +- .../sdk/internal/session/SessionModule.kt | 10 ----- .../sdk/internal/session/room/RoomAPI.kt | 10 ----- .../sdk/internal/session/search/SearchAPI.kt | 36 +++++++++++++++ .../internal/session/search/SearchModule.kt | 44 +++++++++++++++++++ .../sdk/internal/session/search/SearchTask.kt | 5 +-- 6 files changed, 85 insertions(+), 24 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchModule.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt index 475450837e..123b87748f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt @@ -50,6 +50,7 @@ import org.matrix.android.sdk.internal.session.room.send.EncryptEventWorker import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker import org.matrix.android.sdk.internal.session.room.send.SendEventWorker +import org.matrix.android.sdk.internal.session.search.SearchModule import org.matrix.android.sdk.internal.session.signout.SignOutModule import org.matrix.android.sdk.internal.session.sync.SyncModule import org.matrix.android.sdk.internal.session.sync.SyncTask @@ -86,7 +87,8 @@ import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers ProfileModule::class, SessionAssistedInjectModule::class, AccountModule::class, - CallModule::class + CallModule::class, + SearchModule::class ] ) @SessionScope diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index 54478cdc02..5397b8d9bd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.AccountDataService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.permalinks.PermalinkService -import org.matrix.android.sdk.api.session.search.SearchService import org.matrix.android.sdk.api.session.securestorage.SecureStorageService import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService import org.matrix.android.sdk.api.session.typing.TypingUsersTracker @@ -82,10 +81,7 @@ import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkServic import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor import org.matrix.android.sdk.internal.session.room.create.RoomCreateEventProcessor import org.matrix.android.sdk.internal.session.room.prune.RedactionEventProcessor -import org.matrix.android.sdk.internal.session.search.DefaultSearchService import org.matrix.android.sdk.internal.session.room.tombstone.RoomTombstoneEventProcessor -import org.matrix.android.sdk.internal.session.search.DefaultSearchTask -import org.matrix.android.sdk.internal.session.search.SearchTask import org.matrix.android.sdk.internal.session.securestorage.DefaultSecureStorageService import org.matrix.android.sdk.internal.session.typing.DefaultTypingUsersTracker import org.matrix.android.sdk.internal.session.user.accountdata.DefaultAccountDataService @@ -372,10 +368,4 @@ internal abstract class SessionModule { @Binds abstract fun bindTypingUsersTracker(tracker: DefaultTypingUsersTracker): TypingUsersTracker - - @Binds - abstract fun bindSearchService(service: DefaultSearchService): SearchService - - @Binds - abstract fun bindSearchTask(task: DefaultSearchTask): SearchTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index db99adbafb..35c20cf5cb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -35,13 +35,11 @@ import org.matrix.android.sdk.internal.session.room.membership.joining.InviteBod import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody import org.matrix.android.sdk.internal.session.room.relation.RelationsResponse import org.matrix.android.sdk.internal.session.room.reporting.ReportContentBody -import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody import org.matrix.android.sdk.internal.session.room.send.SendResponse import org.matrix.android.sdk.internal.session.room.tags.TagBody import org.matrix.android.sdk.internal.session.room.timeline.EventContextResponse import org.matrix.android.sdk.internal.session.room.timeline.PaginationResponse import org.matrix.android.sdk.internal.session.room.typing.TypingBody -import org.matrix.android.sdk.internal.session.search.response.SearchResponse import retrofit2.Call import retrofit2.http.Body import retrofit2.http.DELETE @@ -367,12 +365,4 @@ internal interface RoomAPI { fun deleteTag(@Path("userId") userId: String, @Path("roomId") roomId: String, @Path("tag") tag: String): Call - - /** - * Performs a full text search across different categories. - */ - @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "search") - fun search( - @Query("next_batch") nextBatch: String?, - @Body body: SearchRequestBody): Call } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt new file mode 100644 index 0000000000..3d5dbc306f --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.internal.session.search + +import org.matrix.android.sdk.internal.network.NetworkConstants +import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody +import org.matrix.android.sdk.internal.session.search.response.SearchResponse +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.POST +import retrofit2.http.Query + +internal interface SearchAPI { + + /** + * Performs a full text search across different categories. + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "search") + fun search( + @Query("next_batch") nextBatch: String?, + @Body body: SearchRequestBody): Call +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchModule.kt new file mode 100644 index 0000000000..50cf8b8d84 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchModule.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 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 org.matrix.android.sdk.internal.session.search + +import dagger.Binds +import dagger.Module +import dagger.Provides +import org.matrix.android.sdk.api.session.search.SearchService +import org.matrix.android.sdk.internal.session.SessionScope +import retrofit2.Retrofit + +@Module +internal abstract class SearchModule { + + @Module + companion object { + @Provides + @JvmStatic + @SessionScope + fun providesSearchAPI(retrofit: Retrofit): SearchAPI { + return retrofit.create(SearchAPI::class.java) + } + } + + @Binds + abstract fun bindSearchService(service: DefaultSearchService): SearchService + + @Binds + abstract fun bindSearchTask(task: DefaultSearchTask): SearchTask +} 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 4502d2a60a..d36fc80d5c 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 @@ -20,7 +20,6 @@ package org.matrix.android.sdk.internal.session.search import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.internal.network.executeRequest -import org.matrix.android.sdk.internal.session.room.RoomAPI 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.SearchRequestEventContext @@ -46,7 +45,7 @@ internal interface SearchTask : Task { } internal class DefaultSearchTask @Inject constructor( - private val roomAPI: RoomAPI, + private val searchAPI: SearchAPI, private val eventBus: EventBus ) : SearchTask { @@ -69,7 +68,7 @@ internal class DefaultSearchTask @Inject constructor( ) ) ) - apiCall = roomAPI.search(params.nextBatch, searchRequestBody) + apiCall = searchAPI.search(params.nextBatch, searchRequestBody) }.toDomain().apply { results = results?.reversed() } } From e21f306635c9cbc110b0992a41bafce0f1220c21 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 28 Sep 2020 19:05:33 +0300 Subject: [PATCH 23/47] Use enum directly instead of its value. --- .../android/sdk/internal/session/search/SearchTask.kt | 2 +- .../internal/session/search/request/SearchRequestOrder.kt | 7 ++++--- .../session/search/request/SearchRequestRoomEvents.kt | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) 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 d36fc80d5c..a2cad6bb2f 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 @@ -55,7 +55,7 @@ internal class DefaultSearchTask @Inject constructor( searchCategories = SearchRequestCategories( roomEvents = SearchRequestRoomEvents( searchTerm = params.searchTerm, - orderBy = if (params.orderByRecent) SearchRequestOrder.RECENT.value else SearchRequestOrder.RANK.value, + orderBy = if (params.orderByRecent) SearchRequestOrder.RECENT else SearchRequestOrder.RANK, filter = SearchRequestFilter( limit = params.limit, rooms = listOf(params.roomId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestOrder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestOrder.kt index eac51ad2df..f0b6f7bc31 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestOrder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestOrder.kt @@ -17,13 +17,14 @@ package org.matrix.android.sdk.internal.session.search.request +import com.squareup.moshi.Json import com.squareup.moshi.JsonClass /** * Represents the order in which to search for results. */ @JsonClass(generateAdapter = false) -internal enum class SearchRequestOrder(val value: String) { - RANK("rank"), - RECENT("recent") +internal enum class SearchRequestOrder { + @Json(name = "rank") RANK, + @Json(name = "recent") RECENT } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt index 26b11e93bd..fef1baa990 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt @@ -29,7 +29,7 @@ internal data class SearchRequestRoomEvents( val filter: SearchRequestFilter? = null, // By default, this is "rank". One of: ["recent", "rank"] @Json(name = "order_by") - val orderBy: String? = null, + val orderBy: SearchRequestOrder? = null, // Configures whether any context for the events returned are included in the response. @Json(name = "event_context") val eventContext: SearchRequestEventContext? = null From 4683dc3f21bc0048f2a8d8f94d7adf9a078f1efc Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 28 Sep 2020 19:55:56 +0300 Subject: [PATCH 24/47] Documentation added to orderByRecent parameter of the search request. --- .../main/java/org/matrix/android/sdk/api/session/room/Room.kt | 1 + .../org/matrix/android/sdk/api/session/search/SearchService.kt | 1 + 2 files changed, 2 insertions(+) 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 a27cdad551..86029e5419 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 @@ -78,6 +78,7 @@ interface Room : * Ref: https://matrix.org/docs/spec/client_server/latest#module-search * @param searchTerm the term to search * @param nextBatch the token that retrieved from the previous response. Should be provided to get the next batch of results + * @param orderByRecent if true, the most recent message events will return in the first places of the list * @param limit the maximum number of events to return. * @param beforeLimit how many events before the result are returned. * @param afterLimit how many events after the result are returned. 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 b089a597e3..0abbdfd958 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 @@ -31,6 +31,7 @@ interface SearchService { * @param searchTerm the term to search * @param roomId the roomId to search term inside * @param nextBatch the token that retrieved from the previous response. Should be provided to get the next batch of results + * @param orderByRecent if true, the most recent message events will return in the first places of the list * @param limit the maximum number of events to return. * @param beforeLimit how many events before the result are returned. * @param afterLimit how many events after the result are returned. From da344fae5190fac24fad4d2ff66a7d92fbe2eb43 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 28 Sep 2020 20:06:39 +0300 Subject: [PATCH 25/47] One case per line. --- .../home/room/detail/RoomDetailViewModel.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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 f8229731d8..1b5e928843 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 @@ -529,16 +529,17 @@ class RoomDetailViewModel @AssistedInject constructor( return@withState false } when (itemId) { - R.id.clear_message_queue -> + R.id.clear_message_queue -> // For now always disable when not in developer mode, worker cancellation is not working properly timeline.pendingEventCount() > 0 && vectorPreferences.developerMode() - R.id.resend_all -> state.asyncRoomSummary()?.hasFailedSending == true - R.id.clear_all -> state.asyncRoomSummary()?.hasFailedSending == true - R.id.open_matrix_apps, R.id.search -> true + R.id.resend_all -> state.asyncRoomSummary()?.hasFailedSending == true + R.id.clear_all -> state.asyncRoomSummary()?.hasFailedSending == true + R.id.open_matrix_apps -> true R.id.voice_call, - R.id.video_call -> true // always show for discoverability - R.id.hangup_call -> webRtcPeerConnectionManager.currentCall != null - else -> false + R.id.video_call -> true // always show for discoverability + R.id.hangup_call -> webRtcPeerConnectionManager.currentCall != null + R.id.search -> true + else -> false } } From 88ca909689e018bb2ad3098378912afa8c6a9109 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 29 Sep 2020 12:37:44 +0300 Subject: [PATCH 26/47] Remove roomId from SearchAction. --- .../app/features/home/room/detail/search/SearchAction.kt | 2 +- .../app/features/home/room/detail/search/SearchFragment.kt | 2 +- .../app/features/home/room/detail/search/SearchViewModel.kt | 2 +- .../app/features/home/room/detail/search/SearchViewState.kt | 5 ++++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt index d295784a8c..4a2c84e258 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt @@ -19,7 +19,7 @@ package im.vector.app.features.home.room.detail.search import im.vector.app.core.platform.VectorViewModelAction sealed class SearchAction : VectorViewModelAction { - data class SearchWith(val roomId: String, val searchTerm: String) : SearchAction() + data class SearchWith(val searchTerm: String) : SearchAction() object ScrolledToTop : SearchAction() object Retry : SearchAction() } 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 fa60d33e64..360a6b6fcc 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 @@ -123,7 +123,7 @@ class SearchFragment @Inject constructor( fun search(query: String) { view?.hideKeyboard() - searchViewModel.handle(SearchAction.SearchWith(fragmentArgs.roomId, query)) + searchViewModel.handle(SearchAction.SearchWith(query)) } override fun onRetryClicked() { 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 67befc80be..5747e83cad 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 @@ -57,7 +57,7 @@ class SearchViewModel @AssistedInject constructor( private fun handleSearchWith(action: SearchAction.SearchWith) { if (action.searchTerm.length > 1) { setState { - copy(searchTerm = action.searchTerm, roomId = action.roomId, isNextBatch = false) + copy(searchTerm = action.searchTerm, isNextBatch = false) } startSearching() 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 02db098e68..8c2eb82ad1 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 @@ -27,4 +27,7 @@ data class SearchViewState( val searchTerm: String? = null, val roomId: String? = null, val isNextBatch: Boolean = false -) : MvRxState +) : MvRxState { + + constructor(args: SearchArgs) : this(roomId = args.roomId) +} From 0d16fe019efd8c1997951ea3a9d6a05f8bf02c68 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 29 Sep 2020 13:00:02 +0300 Subject: [PATCH 27/47] Do not use string provider in fragment. --- .../app/features/home/room/detail/search/SearchFragment.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 360a6b6fcc..1c355bfbfe 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 @@ -33,7 +33,6 @@ import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment -import im.vector.app.core.resources.StringProvider import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_search.* import org.matrix.android.sdk.api.session.events.model.Event @@ -46,8 +45,7 @@ data class SearchArgs( class SearchFragment @Inject constructor( val viewModelFactory: SearchViewModel.Factory, - val controller: SearchResultController, - val stringProvider: StringProvider + val controller: SearchResultController ) : VectorBaseFragment(), StateView.EventCallback, SearchResultController.Listener { private val fragmentArgs: SearchArgs by args() @@ -115,7 +113,7 @@ class SearchFragment @Inject constructor( pendingScrollToPosition = scrollPosition } else { stateView.state = StateView.State.Empty( - title = stringProvider.getString(R.string.search_no_results), + title = getString(R.string.search_no_results), image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search_no_results) ) } From 5d190a81379f7631de18b328c18448fe7f114be0 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 29 Sep 2020 20:38:58 +0300 Subject: [PATCH 28/47] Use loading item instead of full screen loading. --- .../home/room/detail/search/SearchAction.kt | 2 +- .../home/room/detail/search/SearchFragment.kt | 61 ++++++------ .../detail/search/SearchResultController.kt | 17 ++++ .../room/detail/search/SearchViewEvents.kt | 1 - .../room/detail/search/SearchViewModel.kt | 96 +++++++++++-------- .../room/detail/search/SearchViewState.kt | 5 +- .../src/main/res/layout/fragment_search.xml | 3 +- 7 files changed, 104 insertions(+), 81 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt index 4a2c84e258..36d22f1914 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchAction.kt @@ -20,6 +20,6 @@ import im.vector.app.core.platform.VectorViewModelAction sealed class SearchAction : VectorViewModelAction { data class SearchWith(val searchTerm: String) : SearchAction() - object ScrolledToTop : SearchAction() + object LoadMore : SearchAction() object Retry : SearchAction() } 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 1c355bfbfe..5f943c6031 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 @@ -21,14 +21,15 @@ import android.os.Parcelable import android.view.View import androidx.core.content.ContextCompat import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.Success import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith -import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.platform.StateView @@ -62,39 +63,19 @@ class SearchFragment @Inject constructor( stateView.eventCallback = this configureRecyclerView() - - searchViewModel.observeViewEvents { - when (it) { - is SearchViewEvents.Failure -> { - stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(it.throwable)) - } - is SearchViewEvents.Loading -> { - stateView.state = StateView.State.Loading - } - }.exhaustive - } } private fun configureRecyclerView() { searchResultRecycler.trackItemsVisibilityChange() searchResultRecycler.configureWith(controller, showDivider = false) + (searchResultRecycler.layoutManager as? LinearLayoutManager)?.stackFromEnd = true controller.listener = this controller.addModelBuildListener { pendingScrollToPosition?.let { - searchResultRecycler.scrollToPosition(it) + searchResultRecycler.smoothScrollToPosition(it) } } - - searchResultRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - // Load next batch when scrolled to the top - if (newState == RecyclerView.SCROLL_STATE_IDLE - && (searchResultRecycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition() == 0) { - searchViewModel.handle(SearchAction.ScrolledToTop) - } - } - }) } override fun onDestroy() { @@ -104,18 +85,26 @@ class SearchFragment @Inject constructor( } override fun invalidate() = withState(searchViewModel) { state -> - if (state.searchResult?.results?.isNotEmpty() == true) { + if (state.searchResult?.results.isNullOrEmpty()) { + when (state.asyncEventsRequest) { + is Loading -> { + stateView.state = StateView.State.Loading + } + is Fail -> { + stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncEventsRequest.error)) + } + is Success -> { + stateView.state = StateView.State.Empty( + title = getString(R.string.search_no_results), + image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search_no_results)) + } + } + } else { + val lastBatchSize = state.lastBatch?.results?.size ?: 0 + pendingScrollToPosition = if (lastBatchSize > 0) lastBatchSize - 1 else 0 + stateView.state = StateView.State.Content controller.setData(state) - - val lastBatchSize = state.lastBatch?.results?.size ?: 0 - val scrollPosition = if (lastBatchSize > 0) lastBatchSize - 1 else 0 - pendingScrollToPosition = scrollPosition - } else { - stateView.state = StateView.State.Empty( - title = getString(R.string.search_no_results), - image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search_no_results) - ) } } @@ -133,4 +122,8 @@ class SearchFragment @Inject constructor( navigator.openRoom(requireContext(), event.roomId!!, event.eventId) } + + override fun loadMore() { + searchViewModel.handle(SearchAction.LoadMore) + } } 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 82d3120311..39e197e54f 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 @@ -17,8 +17,10 @@ package im.vector.app.features.home.room.detail.search import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.epoxy.VisibilityState import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter +import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.ui.list.genericItemHeader import im.vector.app.features.home.AvatarRenderer import org.matrix.android.sdk.api.session.Session @@ -34,8 +36,11 @@ class SearchResultController @Inject constructor( var listener: Listener? = null + private var idx = 0 + interface Listener { fun onItemClicked(event: Event) + fun loadMore() } init { @@ -45,6 +50,18 @@ class SearchResultController @Inject constructor( override fun buildModels(data: SearchViewState?) { data?.searchResult?.results ?: return + if (!data.searchResult.nextBatch.isNullOrEmpty()) { + loadingItem { + // Always use a different id, because we can be notified several times of visibility state changed + id("loadMore${idx++}") + onVisibilityStateChanged { _, _, visibilityState -> + if (visibilityState == VisibilityState.VISIBLE) { + listener?.loadMore() + } + } + } + } + buildSearchResultItems(data.searchResult.results!!) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt index 41dabd8686..6f07cb765c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewEvents.kt @@ -20,5 +20,4 @@ import im.vector.app.core.platform.VectorViewEvents sealed class SearchViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : SearchViewEvents() - data class Loading(val message: CharSequence? = null) : SearchViewEvents() } 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 5747e83cad..9786560d19 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 @@ -16,16 +16,21 @@ package im.vector.app.features.home.room.detail.search +import androidx.lifecycle.viewModelScope +import com.airbnb.mvrx.Fail 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 import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel -import org.matrix.android.sdk.api.MatrixCallback +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.search.SearchResult +import org.matrix.android.sdk.internal.util.awaitCallback class SearchViewModel @AssistedInject constructor( @Assisted private val initialState: SearchViewState, @@ -48,26 +53,22 @@ class SearchViewModel @AssistedInject constructor( override fun handle(action: SearchAction) { when (action) { - is SearchAction.SearchWith -> handleSearchWith(action) - is SearchAction.ScrolledToTop -> handleScrolledToTop() - is SearchAction.Retry -> handleRetry() + is SearchAction.SearchWith -> handleSearchWith(action) + is SearchAction.LoadMore -> handleLoadMore() + is SearchAction.Retry -> handleRetry() }.exhaustive } private fun handleSearchWith(action: SearchAction.SearchWith) { if (action.searchTerm.length > 1) { setState { - copy(searchTerm = action.searchTerm, isNextBatch = false) + copy(searchTerm = action.searchTerm) } - startSearching() } } - private fun handleScrolledToTop() { - setState { - copy(isNextBatch = true) - } + private fun handleLoadMore() { startSearching(true) } @@ -75,44 +76,51 @@ class SearchViewModel @AssistedInject constructor( startSearching() } - private fun startSearching(scrolledToTop: Boolean = false) = withState { state -> + private fun startSearching(isNextBatch: Boolean = false) = withState { state -> if (state.roomId == null || state.searchTerm == null) return@withState // There is no batch to retrieve - if (scrolledToTop && state.searchResult?.nextBatch == null) return@withState + if (isNextBatch && state.searchResult?.nextBatch == null) return@withState - _viewEvents.post(SearchViewEvents.Loading()) - - session - .getRoom(state.roomId) - ?.search( - searchTerm = state.searchTerm, - nextBatch = state.searchResult?.nextBatch, - orderByRecent = true, - beforeLimit = 0, - afterLimit = 0, - includeProfile = true, - limit = 20, - callback = object : MatrixCallback { - override fun onFailure(failure: Throwable) { - onSearchFailure(failure) - } - - override fun onSuccess(data: SearchResult) { - onSearchResultSuccess(data) - } - } + // Show full screen loading just for the clean search + if (!isNextBatch) { + setState { + copy( + asyncEventsRequest = Loading() ) - } - - private fun onSearchFailure(failure: Throwable) { - setState { - copy(searchResult = null) + } + } + + viewModelScope.launch { + try { + val result = awaitCallback { + session + .getRoom(state.roomId) + ?.search( + searchTerm = state.searchTerm, + nextBatch = state.searchResult?.nextBatch, + orderByRecent = true, + beforeLimit = 0, + afterLimit = 0, + includeProfile = true, + limit = 20, + callback = it + ) + } + onSearchResultSuccess(result, isNextBatch) + } catch (failure: Throwable) { + _viewEvents.post(SearchViewEvents.Failure(failure)) + setState { + copy( + asyncEventsRequest = Fail(failure), + searchResult = null + ) + } + } } - _viewEvents.post(SearchViewEvents.Failure(failure)) } - private fun onSearchResultSuccess(searchResult: SearchResult) = withState { state -> + private fun onSearchResultSuccess(searchResult: SearchResult, isNextBatch: Boolean) = withState { state -> val accumulatedResult = SearchResult( nextBatch = searchResult.nextBatch, results = searchResult.results, @@ -120,7 +128,7 @@ class SearchViewModel @AssistedInject constructor( ) // Accumulate results if it is the next batch - if (state.isNextBatch) { + if (isNextBatch) { if (state.searchResult != null) { accumulatedResult.results = accumulatedResult.results?.plus(state.searchResult.results!!) } @@ -130,7 +138,11 @@ class SearchViewModel @AssistedInject constructor( } setState { - copy(searchResult = accumulatedResult, lastBatch = searchResult) + copy( + searchResult = accumulatedResult, + lastBatch = searchResult, + asyncEventsRequest = Success(Unit) + ) } } } 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 8c2eb82ad1..3873769c44 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 @@ -16,7 +16,9 @@ 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.search.SearchResult data class SearchViewState( @@ -26,7 +28,8 @@ data class SearchViewState( val lastBatch: SearchResult? = null, val searchTerm: String? = null, val roomId: String? = null, - val isNextBatch: Boolean = false + // Current pagination request + val asyncEventsRequest: Async = Uninitialized ) : MvRxState { constructor(args: SearchArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/res/layout/fragment_search.xml b/vector/src/main/res/layout/fragment_search.xml index 5478e1f68c..757168850b 100644 --- a/vector/src/main/res/layout/fragment_search.xml +++ b/vector/src/main/res/layout/fragment_search.xml @@ -2,8 +2,7 @@ + android:layout_height="match_parent"> Date: Tue, 29 Sep 2020 20:46:47 +0300 Subject: [PATCH 29/47] Do not use hard wrapping. --- .../app/features/home/room/detail/search/SearchFragment.kt | 6 +++--- .../home/room/detail/search/SearchResultController.kt | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) 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 5f943c6031..9f024f50f3 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 @@ -118,9 +118,9 @@ class SearchFragment @Inject constructor( } override fun onItemClicked(event: Event) { - event.roomId ?: return - - navigator.openRoom(requireContext(), event.roomId!!, event.eventId) + event.roomId?.let { + navigator.openRoom(requireContext(), it, event.eventId) + } } override fun loadMore() { 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 39e197e54f..cf79ed0ea6 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 @@ -48,9 +48,7 @@ class SearchResultController @Inject constructor( } override fun buildModels(data: SearchViewState?) { - data?.searchResult?.results ?: return - - if (!data.searchResult.nextBatch.isNullOrEmpty()) { + if (!data?.searchResult?.nextBatch.isNullOrEmpty()) { loadingItem { // Always use a different id, because we can be notified several times of visibility state changed id("loadMore${idx++}") @@ -62,7 +60,7 @@ class SearchResultController @Inject constructor( } } - buildSearchResultItems(data.searchResult.results!!) + buildSearchResultItems(data?.searchResult?.results.orEmpty()) } private fun buildSearchResultItems(events: List) { From d4a0659483e8ee12ada1616639be5d52df0e69e5 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 30 Sep 2020 10:58:32 +0300 Subject: [PATCH 30/47] Init room in constructor. --- .../room/detail/search/SearchViewModel.kt | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) 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 9786560d19..62fb9c8ae9 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 @@ -29,6 +29,7 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.internal.util.awaitCallback @@ -37,6 +38,12 @@ class SearchViewModel @AssistedInject constructor( private val session: Session ) : VectorViewModel(initialState) { + private var room: Room? = null + + init { + room = initialState.roomId?.let { session.getRoom(it) } + } + @AssistedInject.Factory interface Factory { fun create(initialState: SearchViewState): SearchViewModel @@ -94,18 +101,16 @@ class SearchViewModel @AssistedInject constructor( viewModelScope.launch { try { val result = awaitCallback { - session - .getRoom(state.roomId) - ?.search( - searchTerm = state.searchTerm, - nextBatch = state.searchResult?.nextBatch, - orderByRecent = true, - beforeLimit = 0, - afterLimit = 0, - includeProfile = true, - limit = 20, - callback = it - ) + room?.search( + searchTerm = state.searchTerm, + nextBatch = state.searchResult?.nextBatch, + orderByRecent = true, + beforeLimit = 0, + afterLimit = 0, + includeProfile = true, + limit = 20, + callback = it + ) } onSearchResultSuccess(result, isNextBatch) } catch (failure: Throwable) { From 0838cbaf03d9e075261e449601a7940f608d62a4 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 30 Sep 2020 11:07:09 +0300 Subject: [PATCH 31/47] UI fixes. --- vector/src/main/res/layout/item_search_result.xml | 4 +++- vector/src/main/res/menu/menu_timeline.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/layout/item_search_result.xml b/vector/src/main/res/layout/item_search_result.xml index 9946a2fb50..73f949f777 100644 --- a/vector/src/main/res/layout/item_search_result.xml +++ b/vector/src/main/res/layout/item_search_result.xml @@ -49,9 +49,11 @@ + app:showAsAction="never" /> Date: Wed, 30 Sep 2020 11:45:46 +0300 Subject: [PATCH 32/47] Cancel previous search task before starting new one. --- .../home/room/detail/search/SearchViewModel.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 62fb9c8ae9..e9cca86e30 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,11 @@ import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel 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.room.Room import org.matrix.android.sdk.api.session.search.SearchResult +import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.internal.util.awaitCallback class SearchViewModel @AssistedInject constructor( @@ -39,6 +41,7 @@ class SearchViewModel @AssistedInject constructor( ) : VectorViewModel(initialState) { private var room: Room? = null + private var currentTask: Cancelable? = null init { room = initialState.roomId?.let { session.getRoom(it) } @@ -98,10 +101,14 @@ class SearchViewModel @AssistedInject constructor( } } + if (state.asyncEventsRequest is Loading) { + currentTask?.cancel() + } + viewModelScope.launch { try { val result = awaitCallback { - room?.search( + currentTask = room?.search( searchTerm = state.searchTerm, nextBatch = state.searchResult?.nextBatch, orderByRecent = true, @@ -114,6 +121,8 @@ class SearchViewModel @AssistedInject constructor( } onSearchResultSuccess(result, isNextBatch) } catch (failure: Throwable) { + if (failure is Failure.Cancelled) return@launch + _viewEvents.post(SearchViewEvents.Failure(failure)) setState { copy( From 6e814678081afc535c8eb32fbf4f0bd31ba24ad0 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 30 Sep 2020 12:39:42 +0300 Subject: [PATCH 33/47] If SearchActivity is in the stack, use it. --- .../app/features/home/room/detail/search/SearchActivity.kt | 1 + 1 file changed, 1 insertion(+) 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 70205eed62..24069a37c3 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,6 +70,7 @@ class SearchActivity : VectorBaseActivity() { fun newIntent(context: Context, args: SearchArgs): Intent { return Intent(context, SearchActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT putExtra(MvRx.KEY_ARG, args) } } From ae346646e4f0fda00eb0810d8f30bd6c0437cc2c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 1 Oct 2020 15:05:42 +0200 Subject: [PATCH 34/47] Cleanup --- .../roomprofile/uploads/RoomUploadsFragment.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt index b3f5047df4..876b585a59 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt @@ -23,23 +23,21 @@ import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.tabs.TabLayoutMediator -import org.matrix.android.sdk.api.util.toMatrixItem import im.vector.app.R import im.vector.app.core.extensions.exhaustive import im.vector.app.core.intent.getMimeTypeFromUri import im.vector.app.core.platform.VectorBaseFragment -import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.saveMedia import im.vector.app.core.utils.shareMedia import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.roomprofile.RoomProfileArgs import kotlinx.android.synthetic.main.fragment_room_uploads.* +import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject class RoomUploadsFragment @Inject constructor( private val viewModelFactory: RoomUploadsViewModel.Factory, - private val stringProvider: StringProvider, private val avatarRenderer: AvatarRenderer, private val notificationUtils: NotificationUtils ) : VectorBaseFragment(), RoomUploadsViewModel.Factory by viewModelFactory { @@ -58,8 +56,8 @@ class RoomUploadsFragment @Inject constructor( TabLayoutMediator(roomUploadsTabs, roomUploadsViewPager) { tab, position -> when (position) { - 0 -> tab.text = stringProvider.getString(R.string.uploads_media_title) - 1 -> tab.text = stringProvider.getString(R.string.uploads_files_title) + 0 -> tab.text = getString(R.string.uploads_media_title) + 1 -> tab.text = getString(R.string.uploads_files_title) } }.attach() @@ -70,7 +68,7 @@ class RoomUploadsFragment @Inject constructor( is RoomUploadsViewEvents.FileReadyForSharing -> { shareMedia(requireContext(), it.file, getMimeTypeFromUri(requireContext(), it.file.toUri())) } - is RoomUploadsViewEvents.FileReadyForSaving -> { + is RoomUploadsViewEvents.FileReadyForSaving -> { saveMedia( context = requireContext(), file = it.file, @@ -79,7 +77,7 @@ class RoomUploadsFragment @Inject constructor( notificationUtils = notificationUtils ) } - is RoomUploadsViewEvents.Failure -> showFailure(it.throwable) + is RoomUploadsViewEvents.Failure -> showFailure(it.throwable) }.exhaustive } } From 4649b2ac1daad64e04c2c1a290f7c3e521653297 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 1 Oct 2020 16:09:06 +0200 Subject: [PATCH 35/47] Code review --- .../sdk/api/session/search/SearchResult.kt | 17 ++++-- .../sdk/internal/session/DefaultSession.kt | 4 +- .../sdk/internal/session/search/SearchAPI.kt | 6 +- .../sdk/internal/session/search/SearchTask.kt | 4 +- .../search/request/SearchRequestBody.kt | 3 + .../search/request/SearchRequestCategories.kt | 4 +- .../search/request/SearchRequestRoomEvents.kt | 37 +++++++++++-- .../session/search/response/SearchResponse.kt | 6 +- .../response/SearchResponseCategories.kt | 5 +- .../search/response/SearchResponseItem.kt | 19 +++++-- .../response/SearchResponseRoomEvents.kt | 2 +- .../home/room/detail/search/SearchFragment.kt | 10 ++-- .../detail/search/SearchResultController.kt | 13 ++--- .../room/detail/search/SearchResultItem.kt | 24 ++++---- .../room/detail/search/SearchViewModel.kt | 55 ++++++++----------- .../room/detail/search/SearchViewState.kt | 11 ++-- .../src/main/res/layout/activity_search.xml | 4 +- .../src/main/res/layout/fragment_search.xml | 4 +- 18 files changed, 138 insertions(+), 90 deletions(-) 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 4529bf6d13..59d1c4d46d 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 @@ -23,10 +23,17 @@ import org.matrix.android.sdk.api.session.events.model.Event * Domain class to represent the response of a search request in a room. */ data class SearchResult( - // Token that can be used to get the next batch of results, by passing as the next_batch parameter to the next call. If this field is absent, there are no more results. + /** + * Token that can be used to get the next batch of results, by passing as the next_batch parameter to the next call. + * If this field is null, there are no more results. + */ val nextBatch: String? = null, - // List of words which should be highlighted, useful for stemming which may change the query terms. - var highlights: List? = null, - // List of results in the requested order. - var results: List? = null + /** + * List of words which should be highlighted, useful for stemming which may change the query terms. + */ + val highlights: List? = null, + /** + * List of results in the requested order. + */ + val results: List? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 34b6be225b..d1c0844caa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -96,6 +96,7 @@ internal class DefaultSession @Inject constructor( private val pushRuleService: Lazy, private val pushersService: Lazy, private val termsService: Lazy, + private val searchService: Lazy, private val cryptoService: Lazy, private val defaultFileService: Lazy, private val permalinkService: Lazy, @@ -121,8 +122,7 @@ internal class DefaultSession @Inject constructor( private val taskExecutor: TaskExecutor, private val callSignalingService: Lazy, @UnauthenticatedWithCertificate - private val unauthenticatedWithCertificateOkHttpClient: Lazy, - private val searchService: Lazy + private val unauthenticatedWithCertificateOkHttpClient: Lazy ) : Session, RoomService by roomService.get(), RoomDirectoryService by roomDirectoryService.get(), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt index 3d5dbc306f..a903cd8cc8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt @@ -28,9 +28,9 @@ internal interface SearchAPI { /** * Performs a full text search across different categories. + * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-search */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "search") - fun search( - @Query("next_batch") nextBatch: String?, - @Body body: SearchRequestBody): Call + fun search(@Query("next_batch") nextBatch: String?, + @Body body: SearchRequestBody): Call } 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 a2cad6bb2f..3bb65fb8da 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 @@ -69,14 +69,14 @@ internal class DefaultSearchTask @Inject constructor( ) ) apiCall = searchAPI.search(params.nextBatch, searchRequestBody) - }.toDomain().apply { results = results?.reversed() } + }.toDomain() } private fun SearchResponse.toDomain(): SearchResult { return SearchResult( nextBatch = searchCategories.roomEvents?.nextBatch, highlights = searchCategories.roomEvents?.highlights, - results = searchCategories.roomEvents?.results?.map { it.event } + results = searchCategories.roomEvents?.results?.map { it.event }?.reversed() ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestBody.kt index 000f89e751..7cf86457d6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestBody.kt @@ -22,6 +22,9 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class SearchRequestBody( + /** + * Required. Describes which categories to search in and their criteria. + */ @Json(name = "search_categories") val searchCategories: SearchRequestCategories ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestCategories.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestCategories.kt index 606b7320e5..9d87114237 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestCategories.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestCategories.kt @@ -22,7 +22,9 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class SearchRequestCategories( - // Mapping of category name to search criteria. + /** + * Mapping of category name to search criteria. + */ @Json(name = "room_events") val roomEvents: SearchRequestRoomEvents? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt index fef1baa990..c5234b1052 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt @@ -22,15 +22,44 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class SearchRequestRoomEvents( - // Required. The string to search events for. + /** + * Required. The string to search events for. + */ @Json(name = "search_term") val searchTerm: String, + + /** + * The keys to search. Defaults to all. One of: ["content.body", "content.name", "content.topic"] + */ + @Json(name = "keys") + val keys: Any? = null, + + /** + * This takes a filter. + */ @Json(name = "filter") val filter: SearchRequestFilter? = null, - // By default, this is "rank". One of: ["recent", "rank"] + + /** + * The order in which to search for results. By default, this is "rank". One of: ["recent", "rank"] + */ @Json(name = "order_by") val orderBy: SearchRequestOrder? = null, - // Configures whether any context for the events returned are included in the response. + + /** + * Configures whether any context for the events returned are included in the response. + */ @Json(name = "event_context") - val eventContext: SearchRequestEventContext? = null + val eventContext: SearchRequestEventContext? = null, + + /** + * Requests the server return the current state for each room returned. + */ + @Json(name = "include_state") + val include_state: Boolean? = null + + /** + * Requests that the server partitions the result set based on the provided list of keys. + */ + // val groupings: SearchRequestGroupings? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponse.kt index b7debb6b1e..8e11ba1468 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponse.kt @@ -21,8 +21,10 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchResponse( - // Required. Describes which categories to search in and their criteria. +internal data class SearchResponse( + /** + * Required. Describes which categories to search in and their criteria. + */ @Json(name = "search_categories") val searchCategories: SearchResponseCategories ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseCategories.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseCategories.kt index c931b23826..8e46502e27 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseCategories.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseCategories.kt @@ -21,7 +21,10 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class SearchResponseCategories( +internal data class SearchResponseCategories( + /** + * Mapping of category name to search criteria. + */ @Json(name = "room_events") val roomEvents: SearchResponseRoomEvents? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseItem.kt index 7c675f0593..5b0806ce85 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseItem.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseItem.kt @@ -22,11 +22,22 @@ import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.session.events.model.Event @JsonClass(generateAdapter = true) -data class SearchResponseItem( - // A number that describes how closely this result matches the search. Higher is closer. +internal data class SearchResponseItem( + /** + * A number that describes how closely this result matches the search. Higher is closer. + */ @Json(name = "rank") val rank: Double? = null, - // The event that matched. + + /** + * The event that matched. + */ @Json(name = "result") - val event: Event + val event: Event, + + /** + * Context for result, if requested. + */ + @Json(name = "context") + val context: SearchResponseEventContext? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt index 61ed2bf3cf..1078b9a9f9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt @@ -21,7 +21,7 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -class SearchResponseRoomEvents( +internal data class SearchResponseRoomEvents( // List of results in the requested order. @Json(name = "results") val results: List? = null, 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 9f024f50f3..ea7ba8f464 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 @@ -46,7 +46,7 @@ data class SearchArgs( class SearchFragment @Inject constructor( val viewModelFactory: SearchViewModel.Factory, - val controller: SearchResultController + private val controller: SearchResultController ) : VectorBaseFragment(), StateView.EventCallback, SearchResultController.Listener { private val fragmentArgs: SearchArgs by args() @@ -85,13 +85,13 @@ class SearchFragment @Inject constructor( } override fun invalidate() = withState(searchViewModel) { state -> - if (state.searchResult?.results.isNullOrEmpty()) { - when (state.asyncEventsRequest) { + if (state.searchResult.isNullOrEmpty()) { + when (state.asyncSearchRequest) { is Loading -> { stateView.state = StateView.State.Loading } is Fail -> { - stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncEventsRequest.error)) + stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error)) } is Success -> { stateView.state = StateView.State.Empty( @@ -100,7 +100,7 @@ class SearchFragment @Inject constructor( } } } else { - val lastBatchSize = state.lastBatch?.results?.size ?: 0 + val lastBatchSize = state.lastBatch?.size ?: 0 pendingScrollToPosition = if (lastBatchSize > 0) lastBatchSize - 1 else 0 stateView.state = StateView.State.Content 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 cf79ed0ea6..8daa4f60e4 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 @@ -48,7 +48,9 @@ class SearchResultController @Inject constructor( } override fun buildModels(data: SearchViewState?) { - if (!data?.searchResult?.nextBatch.isNullOrEmpty()) { + data ?: return + + if (data.hasMoreResult) { loadingItem { // Always use a different id, because we can be notified several times of visibility state changed id("loadMore${idx++}") @@ -60,7 +62,7 @@ class SearchResultController @Inject constructor( } } - buildSearchResultItems(data?.searchResult?.results.orEmpty()) + buildSearchResultItems(data.searchResult.orEmpty()) } private fun buildSearchResultItems(events: List) { @@ -83,12 +85,9 @@ class SearchResultController @Inject constructor( 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(object : SearchResultItem.Listener { - override fun onItemClicked() { - listener?.onItemClicked(event) - } - }) + listener { listener?.onItemClicked(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 fb0121cbcf..2d569c1c6a 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 @@ -23,8 +23,10 @@ import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter +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.features.home.AvatarRenderer import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.user.model.User @@ -33,21 +35,21 @@ import org.matrix.android.sdk.api.util.toMatrixItem @EpoxyModelClass(layout = R.layout.item_search_result) abstract class SearchResultItem : VectorEpoxyModel() { - @EpoxyAttribute var avatarRenderer: AvatarRenderer? = null + @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute var dateFormatter: VectorDateFormatter? = null - @EpoxyAttribute var event: Event? = null + @EpoxyAttribute lateinit var event: Event @EpoxyAttribute var sender: User? = null - @EpoxyAttribute var listener: Listener? = null + @EpoxyAttribute var listener: ClickListener? = null override fun bind(holder: Holder) { super.bind(holder) - event ?: return - holder.view.setOnClickListener { listener?.onItemClicked() } - sender?.toMatrixItem()?.let { avatarRenderer?.render(it, holder.avatarImageView) } - holder.memberNameView.text = sender?.displayName - holder.timeView.text = dateFormatter?.format(event!!.originServerTs, DateFormatKind.MESSAGE_SIMPLE) - holder.contentView.text = event?.content?.get("body") as? String + holder.view.onClick(listener) + sender?.toMatrixItem()?.let { avatarRenderer.render(it, holder.avatarImageView) } + holder.memberNameView.text = 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 } class Holder : VectorEpoxyHolder() { @@ -56,8 +58,4 @@ abstract class SearchResultItem : VectorEpoxyModel() { val timeView by bind(R.id.messageTimeView) val contentView by bind(R.id.messageContentView) } - - interface Listener { - fun onItemClicked() - } } 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 e9cca86e30..6703815f57 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 @@ -37,15 +37,14 @@ import org.matrix.android.sdk.internal.util.awaitCallback class SearchViewModel @AssistedInject constructor( @Assisted private val initialState: SearchViewState, - private val session: Session + session: Session ) : VectorViewModel(initialState) { - private var room: Room? = null + private var room: Room? = session.getRoom(initialState.roomId) + private var currentTask: Cancelable? = null - init { - room = initialState.roomId?.let { session.getRoom(it) } - } + private var nextBatch: String? = null @AssistedInject.Factory interface Factory { @@ -64,8 +63,8 @@ class SearchViewModel @AssistedInject constructor( override fun handle(action: SearchAction) { when (action) { is SearchAction.SearchWith -> handleSearchWith(action) - is SearchAction.LoadMore -> handleLoadMore() - is SearchAction.Retry -> handleRetry() + is SearchAction.LoadMore -> handleLoadMore() + is SearchAction.Retry -> handleRetry() }.exhaustive } @@ -74,7 +73,7 @@ class SearchViewModel @AssistedInject constructor( setState { copy(searchTerm = action.searchTerm) } - startSearching() + startSearching(false) } } @@ -83,25 +82,25 @@ class SearchViewModel @AssistedInject constructor( } private fun handleRetry() { - startSearching() + startSearching(false) } - private fun startSearching(isNextBatch: Boolean = false) = withState { state -> - if (state.roomId == null || state.searchTerm == null) return@withState + private fun startSearching(isNextBatch: Boolean) = withState { state -> + if (state.searchTerm == null) return@withState // There is no batch to retrieve - if (isNextBatch && state.searchResult?.nextBatch == null) return@withState + if (isNextBatch && nextBatch == null) return@withState // Show full screen loading just for the clean search if (!isNextBatch) { setState { copy( - asyncEventsRequest = Loading() + asyncSearchRequest = Loading() ) } } - if (state.asyncEventsRequest is Loading) { + if (state.asyncSearchRequest is Loading) { currentTask?.cancel() } @@ -110,7 +109,7 @@ class SearchViewModel @AssistedInject constructor( val result = awaitCallback { currentTask = room?.search( searchTerm = state.searchTerm, - nextBatch = state.searchResult?.nextBatch, + nextBatch = nextBatch, orderByRecent = true, beforeLimit = 0, afterLimit = 0, @@ -126,7 +125,7 @@ class SearchViewModel @AssistedInject constructor( _viewEvents.post(SearchViewEvents.Failure(failure)) setState { copy( - asyncEventsRequest = Fail(failure), + asyncSearchRequest = Fail(failure), searchResult = null ) } @@ -135,27 +134,19 @@ class SearchViewModel @AssistedInject constructor( } private fun onSearchResultSuccess(searchResult: SearchResult, isNextBatch: Boolean) = withState { state -> - val accumulatedResult = SearchResult( - nextBatch = searchResult.nextBatch, - results = searchResult.results, - highlights = searchResult.highlights - ) - // Accumulate results if it is the next batch - if (isNextBatch) { - if (state.searchResult != null) { - accumulatedResult.results = accumulatedResult.results?.plus(state.searchResult.results!!) - } - if (state.searchResult?.highlights != null) { - accumulatedResult.highlights = accumulatedResult.highlights?.plus(state.searchResult.highlights!!) - } - } + 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 + + nextBatch = searchResult.nextBatch setState { copy( searchResult = accumulatedResult, - lastBatch = searchResult, - asyncEventsRequest = Success(Unit) + hasMoreResult = !nextBatch.isNullOrEmpty(), + lastBatch = searchResult.results, + asyncSearchRequest = Success(Unit) ) } } 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 3873769c44..72da1ca940 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,17 +19,18 @@ 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.search.SearchResult +import org.matrix.android.sdk.api.session.events.model.Event data class SearchViewState( // Accumulated search result - val searchResult: SearchResult? = null, + val searchResult: List? = null, + val hasMoreResult: Boolean = false, // Last batch result will help RecyclerView to position itself - val lastBatch: SearchResult? = null, + val lastBatch: List? = null, val searchTerm: String? = null, - val roomId: String? = null, + val roomId: String = "", // Current pagination request - val asyncEventsRequest: Async = Uninitialized + val asyncSearchRequest: Async = Uninitialized ) : MvRxState { constructor(args: SearchArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/res/layout/activity_search.xml b/vector/src/main/res/layout/activity_search.xml index a3aa21eecc..2268bf932c 100644 --- a/vector/src/main/res/layout/activity_search.xml +++ b/vector/src/main/res/layout/activity_search.xml @@ -24,8 +24,8 @@ style="@style/VectorSearchView" android:layout_width="match_parent" android:layout_height="wrap_content" - app:queryHint="@string/search_hint" - android:backgroundTint="@color/base_color" /> + android:backgroundTint="@color/base_color" + app:queryHint="@string/search_hint" /> diff --git a/vector/src/main/res/layout/fragment_search.xml b/vector/src/main/res/layout/fragment_search.xml index 757168850b..330e70d86b 100644 --- a/vector/src/main/res/layout/fragment_search.xml +++ b/vector/src/main/res/layout/fragment_search.xml @@ -1,5 +1,6 @@ @@ -8,6 +9,7 @@ android:id="@+id/searchResultRecycler" android:layout_width="match_parent" android:layout_height="match_parent" - android:overScrollMode="always" /> + android:overScrollMode="always" + tools:listitem="@layout/item_search_result" /> \ No newline at end of file From 3705fa14bd863108e48b9e820f23ff00ad71cba8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 1 Oct 2020 17:03:53 +0200 Subject: [PATCH 36/47] 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 From f030e098a8a8438413f564c50703609c18e71ac1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 17:18:39 +0200 Subject: [PATCH 37/47] Fix code quality and compilation test --- .../sdk/session/search/SearchMessagesTest.kt | 4 ++-- .../search/response/SearchResponseRoomEvents.kt | 13 ++++++++++--- tools/check/forbidden_strings_in_code.txt | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt index 1d4eb758ed..8ae8ef1b44 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt @@ -90,7 +90,7 @@ class SearchMessagesTest : InstrumentedTest { assertTrue( data.results ?.all { - (it.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() + (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() }.orFalse() ) lock.countDown() @@ -154,7 +154,7 @@ class SearchMessagesTest : InstrumentedTest { assertTrue( data.results ?.all { - (it.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() + (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() }.orFalse() ) lock.countDown() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt index 1078b9a9f9..2aac427232 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/response/SearchResponseRoomEvents.kt @@ -22,15 +22,22 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class SearchResponseRoomEvents( - // List of results in the requested order. + /** + * List of results in the requested order. + */ @Json(name = "results") val results: List? = null, @Json(name = "count") val count: Int? = null, - // List of words which should be highlighted, useful for stemming which may change the query terms. + /** + * List of words which should be highlighted, useful for stemming which may change the query terms. + */ @Json(name = "highlights") val highlights: List? = null, - // Token that can be used to get the next batch of results, by passing as the next_batch parameter to the next call. If this field is absent, there are no more results. + /** + * Token that can be used to get the next batch of results, by passing as the next_batch parameter to the next call. + * If this field is absent, there are no more results. + */ @Json(name = "next_batch") val nextBatch: String? = null ) diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index 1d3aaa9f69..9c00dca278 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -164,7 +164,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If it is ok, change the value in file forbidden_strings_in_code.txt -enum class===80 +enum class===81 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3 From 85417eb24c2dff8039ac3fb5c9a8227ebb7b29b3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 21:12:19 +0200 Subject: [PATCH 38/47] Add SearchView to filter members. Author: Onuray (I squashed 2 commits) --- CHANGES.md | 1 + .../members/RoomMemberListAction.kt | 1 + .../members/RoomMemberListController.kt | 4 ++- .../members/RoomMemberListFragment.kt | 17 +++++++++++++ .../members/RoomMemberListViewModel.kt | 25 +++++++++++++++++++ .../members/RoomMemberListViewState.kt | 1 + .../layout/fragment_room_setting_generic.xml | 14 ++++++++++- 7 files changed, 61 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4a158086a2..f5d6fca073 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Improvements 🙌: - Small optimisation of scrolling experience in timeline (#2114) - Allow user to reset cross signing if he has no way to recover (#2052) - Create home shortcut for any room (#1525) + - Filter room member by name (#2184) Bugfix 🐛: - Improve support for image/audio/video/file selection with intent changes (#1376) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListAction.kt index c61dcb98f5..342a2e8585 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListAction.kt @@ -20,4 +20,5 @@ import im.vector.app.core.platform.VectorViewModelAction sealed class RoomMemberListAction : VectorViewModelAction { data class RevokeThreePidInvite(val stateKey: String) : RoomMemberListAction() + data class FilterMemberList(val searchTerm: String) : RoomMemberListAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt index 59b1bca26f..f0c7e146c6 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt @@ -53,7 +53,9 @@ class RoomMemberListController @Inject constructor( } override fun buildModels(data: RoomMemberListViewState?) { - val roomMembersByPowerLevel = data?.roomMemberSummaries?.invoke() ?: return + data ?: return + + val roomMembersByPowerLevel = data.filteredRoomMemberSummaries ?: data.roomMemberSummaries.invoke() ?: return val threePidInvites = data.threePidInvites().orEmpty() var threePidInvitesDone = threePidInvites.isEmpty() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt index 46d0f35b95..e12cce9484 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt @@ -21,6 +21,8 @@ import android.view.Menu import android.view.MenuItem import android.view.View import androidx.appcompat.app.AlertDialog +import androidx.appcompat.widget.SearchView +import androidx.core.view.isVisible import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -72,12 +74,27 @@ class RoomMemberListFragment @Inject constructor( super.onViewCreated(view, savedInstanceState) roomMemberListController.callback = this setupToolbar(roomSettingsToolbar) + setupSearchView() recyclerView.configureWith(roomMemberListController, hasFixedSize = true) viewModel.selectSubscribe(this, RoomMemberListViewState::actionsPermissions) { invalidateOptionsMenu() } } + private fun setupSearchView() { + searchView.isVisible = true + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return true + } + + override fun onQueryTextChange(newText: String): Boolean { + viewModel.handle(RoomMemberListAction.FilterMemberList(newText)) + return true + } + }) + } + override fun onDestroyView() { recyclerView.cleanup() super.onDestroyView() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt index fedf1729ad..c45dbb1093 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt @@ -188,6 +188,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState override fun handle(action: RoomMemberListAction) { when (action) { is RoomMemberListAction.RevokeThreePidInvite -> handleRevokeThreePidInvite(action) + is RoomMemberListAction.FilterMemberList -> handleFilterMemberList(action) }.exhaustive } @@ -201,4 +202,28 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState ) } } + + private fun handleFilterMemberList(action: RoomMemberListAction.FilterMemberList) = withState { state -> + if (action.searchTerm.isBlank()) { + setState { copy(filteredRoomMemberSummaries = null) } + return@withState + } + val roomMemberSummaries = state.roomMemberSummaries.invoke() + roomMemberSummaries + ?.mapNotNull { (powerLevelCategory, roomMemberList) -> + roomMemberList + .filter { it.displayName?.contains(action.searchTerm).orFalse() || it.userId.contains(action.searchTerm) } + .takeIf { it.isNotEmpty() } + ?.let { filteredMemberList -> + Pair(powerLevelCategory, filteredMemberList) + } + } + ?.also { filteredRoomMemberSummaries -> + setState { + copy( + filteredRoomMemberSummaries = filteredRoomMemberSummaries + ) + } + } + } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt index 4d21aa103f..01fd290e78 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt @@ -31,6 +31,7 @@ data class RoomMemberListViewState( val roomId: String, val roomSummary: Async = Uninitialized, val roomMemberSummaries: Async = Uninitialized, + val filteredRoomMemberSummaries: RoomMemberSummaries? = null, val threePidInvites: Async> = Uninitialized, val trustLevelMap: Async> = Uninitialized, val actionsPermissions: ActionPermissions = ActionPermissions() diff --git a/vector/src/main/res/layout/fragment_room_setting_generic.xml b/vector/src/main/res/layout/fragment_room_setting_generic.xml index aa86ee342b..cdbf678b2b 100644 --- a/vector/src/main/res/layout/fragment_room_setting_generic.xml +++ b/vector/src/main/res/layout/fragment_room_setting_generic.xml @@ -53,6 +53,18 @@ + + From 78ed184f60381c529b287bea20f3a33975ccb661 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 21:40:10 +0200 Subject: [PATCH 39/47] Filter in the controller, to keep a live members list --- .../members/RoomMemberListController.kt | 24 +++++++----- .../members/RoomMemberListViewModel.kt | 26 +++---------- .../members/RoomMemberListViewState.kt | 2 +- .../members/RoomMemberSummaryFilter.kt | 37 +++++++++++++++++++ 4 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt index f0c7e146c6..0d4b732da9 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt @@ -17,12 +17,6 @@ package im.vector.app.features.roomprofile.members import com.airbnb.epoxy.TypedEpoxyController -import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary -import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent -import org.matrix.android.sdk.api.util.MatrixItem -import org.matrix.android.sdk.api.util.toMatrixItem import im.vector.app.R import im.vector.app.core.epoxy.dividerItem import im.vector.app.core.epoxy.profiles.buildProfileSection @@ -31,11 +25,18 @@ import im.vector.app.core.extensions.join import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider 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.toModel +import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary +import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent +import org.matrix.android.sdk.api.util.MatrixItem +import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject class RoomMemberListController @Inject constructor( private val avatarRenderer: AvatarRenderer, private val stringProvider: StringProvider, + private val roomMemberSummaryFilter: RoomMemberSummaryFilter, colorProvider: ColorProvider ) : TypedEpoxyController() { @@ -55,17 +56,20 @@ class RoomMemberListController @Inject constructor( override fun buildModels(data: RoomMemberListViewState?) { data ?: return - val roomMembersByPowerLevel = data.filteredRoomMemberSummaries ?: data.roomMemberSummaries.invoke() ?: return + roomMemberSummaryFilter.filter = data.filter + + val roomMembersByPowerLevel = data.roomMemberSummaries.invoke() ?: return val threePidInvites = data.threePidInvites().orEmpty() var threePidInvitesDone = threePidInvites.isEmpty() for ((powerLevelCategory, roomMemberList) in roomMembersByPowerLevel) { - if (roomMemberList.isEmpty()) { + val filteredRoomMemberList = roomMemberList.filter { roomMemberSummaryFilter.test(it) } + if (filteredRoomMemberList.isEmpty()) { continue } if (powerLevelCategory == RoomMemberListCategories.USER && !threePidInvitesDone) { - // If there is not regular invite, display threepid invite before the regular user + // If there is no regular invite, display threepid invite before the regular user buildProfileSection( stringProvider.getString(RoomMemberListCategories.INVITE.titleRes) ) @@ -77,7 +81,7 @@ class RoomMemberListController @Inject constructor( buildProfileSection( stringProvider.getString(powerLevelCategory.titleRes) ) - roomMemberList.join( + filteredRoomMemberList.join( each = { _, roomMember -> profileMatrixItem { id(roomMember.userId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt index c45dbb1093..60cb5867a7 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt @@ -203,27 +203,11 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState } } - private fun handleFilterMemberList(action: RoomMemberListAction.FilterMemberList) = withState { state -> - if (action.searchTerm.isBlank()) { - setState { copy(filteredRoomMemberSummaries = null) } - return@withState + private fun handleFilterMemberList(action: RoomMemberListAction.FilterMemberList) = withState { + setState { + copy( + filter = action.searchTerm + ) } - val roomMemberSummaries = state.roomMemberSummaries.invoke() - roomMemberSummaries - ?.mapNotNull { (powerLevelCategory, roomMemberList) -> - roomMemberList - .filter { it.displayName?.contains(action.searchTerm).orFalse() || it.userId.contains(action.searchTerm) } - .takeIf { it.isNotEmpty() } - ?.let { filteredMemberList -> - Pair(powerLevelCategory, filteredMemberList) - } - } - ?.also { filteredRoomMemberSummaries -> - setState { - copy( - filteredRoomMemberSummaries = filteredRoomMemberSummaries - ) - } - } } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt index 01fd290e78..787ae920e1 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt @@ -31,7 +31,7 @@ data class RoomMemberListViewState( val roomId: String, val roomSummary: Async = Uninitialized, val roomMemberSummaries: Async = Uninitialized, - val filteredRoomMemberSummaries: RoomMemberSummaries? = null, + val filter: String = "", val threePidInvites: Async> = Uninitialized, val trustLevelMap: Async> = Uninitialized, val actionsPermissions: ActionPermissions = ActionPermissions() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt new file mode 100644 index 0000000000..813679fef3 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 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.features.roomprofile.members + +import io.reactivex.functions.Predicate +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary +import javax.inject.Inject + +class RoomMemberSummaryFilter @Inject constructor() : Predicate { + var filter: String = "" + + override fun test(roomMemberSummary: RoomMemberSummary): Boolean { + if (filter.isBlank()) { + // No filter + return true + } + + return roomMemberSummary.displayName?.contains(filter, ignoreCase = true).orFalse() + // We should maybe exclude the domain from the userId + || roomMemberSummary.userId.contains(filter, ignoreCase = true) + } +} From 9df3de2afb33fcf3e8adcd75157e24d3faa98e6c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 21:50:01 +0200 Subject: [PATCH 40/47] Rename method --- .../features/roomprofile/members/RoomMemberListController.kt | 4 ++-- .../features/roomprofile/members/RoomMemberListFragment.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt index 0d4b732da9..ee6b9a71bf 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt @@ -42,7 +42,7 @@ class RoomMemberListController @Inject constructor( interface Callback { fun onRoomMemberClicked(roomMember: RoomMemberSummary) - fun onThreePidInvites(event: Event) + fun onThreePidInviteClicked(event: Event) } private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color) @@ -134,7 +134,7 @@ class RoomMemberListController @Inject constructor( avatarRenderer(avatarRenderer) editable(data.actionsPermissions.canRevokeThreePidInvite) clickListener { _ -> - callback?.onThreePidInvites(event) + callback?.onThreePidInviteClicked(event) } } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt index e12cce9484..5367788466 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt @@ -109,7 +109,7 @@ class RoomMemberListFragment @Inject constructor( navigator.openRoomMemberProfile(roomMember.userId, roomId = roomProfileArgs.roomId, context = requireActivity()) } - override fun onThreePidInvites(event: Event) { + override fun onThreePidInviteClicked(event: Event) { // Display a dialog to revoke invite if power level is high enough val content = event.content.toModel() ?: return val stateKey = event.stateKey ?: return From f5580212ea51e1d961ab023aa3253ca8439211c2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 22:16:13 +0200 Subject: [PATCH 41/47] Also filter threePids --- .../roomprofile/members/RoomMemberListController.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt index ee6b9a71bf..71ac7fcec4 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt @@ -59,7 +59,14 @@ class RoomMemberListController @Inject constructor( roomMemberSummaryFilter.filter = data.filter val roomMembersByPowerLevel = data.roomMemberSummaries.invoke() ?: return - val threePidInvites = data.threePidInvites().orEmpty() + val threePidInvites = data.threePidInvites() + ?.filter { event -> + event.content.toModel() + ?.takeIf { + data.filter.isEmpty() || it.displayName.contains(data.filter, ignoreCase = true) + } != null + } + .orEmpty() var threePidInvitesDone = threePidInvites.isEmpty() for ((powerLevelCategory, roomMemberList) in roomMembersByPowerLevel) { @@ -100,12 +107,13 @@ class RoomMemberListController @Inject constructor( } } ) - if (powerLevelCategory == RoomMemberListCategories.INVITE) { + if (powerLevelCategory == RoomMemberListCategories.INVITE && !threePidInvitesDone) { // Display the threepid invite after the regular invite dividerItem { id("divider_threepidinvites") color(dividerColor) } + buildThreePidInvites(data) threePidInvitesDone = true } From 50f6a4732c40b89622e3ba28a194ef71f242124b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 22:21:13 +0200 Subject: [PATCH 42/47] Change hint --- .../features/roomprofile/members/RoomMemberListFragment.kt | 1 + .../src/main/res/layout/fragment_room_setting_generic.xml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt index 5367788466..e4d17b4da6 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt @@ -83,6 +83,7 @@ class RoomMemberListFragment @Inject constructor( private fun setupSearchView() { searchView.isVisible = true + searchView.queryHint = getString(R.string.search_members_hint) searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { return true diff --git a/vector/src/main/res/layout/fragment_room_setting_generic.xml b/vector/src/main/res/layout/fragment_room_setting_generic.xml index cdbf678b2b..03e211a806 100644 --- a/vector/src/main/res/layout/fragment_room_setting_generic.xml +++ b/vector/src/main/res/layout/fragment_room_setting_generic.xml @@ -59,11 +59,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" + android:background="@null" android:visibility="gone" - tools:visibility="visible" - app:queryHint="@string/search_hint" app:layout_constraintTop_toBottomOf="@id/roomSettingsToolbar" - android:background="@null" /> + tools:queryHint="@string/search_hint" + tools:visibility="visible" /> Date: Fri, 2 Oct 2020 23:06:59 +0200 Subject: [PATCH 43/47] Hide the SearchView when scrolling down --- .../members/RoomMemberListFragment.kt | 2 +- .../layout/fragment_room_setting_generic.xml | 52 +++++++++++++------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt index e4d17b4da6..67577e866e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt @@ -82,7 +82,7 @@ class RoomMemberListFragment @Inject constructor( } private fun setupSearchView() { - searchView.isVisible = true + searchViewAppBarLayout.isVisible = true searchView.queryHint = getString(R.string.search_members_hint) searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { diff --git a/vector/src/main/res/layout/fragment_room_setting_generic.xml b/vector/src/main/res/layout/fragment_room_setting_generic.xml index 03e211a806..4ab6d2c7df 100644 --- a/vector/src/main/res/layout/fragment_room_setting_generic.xml +++ b/vector/src/main/res/layout/fragment_room_setting_generic.xml @@ -53,28 +53,46 @@ - - - + app:layout_constraintTop_toBottomOf="@+id/roomSettingsToolbar"> + + + + + + + + + + From c0842d4da70e56eeb1fa20ec6d6661a09e0c6497 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 23:20:28 +0200 Subject: [PATCH 44/47] Also apply the filter to banned user screen --- CHANGES.md | 2 +- .../banned/RoomBannedListMemberAction.kt | 1 + .../banned/RoomBannedListMemberViewModel.kt | 10 ++++ .../banned/RoomBannedMemberListController.kt | 59 ++++++++++--------- .../banned/RoomBannedMemberListFragment.kt | 18 ++++++ .../banned/RoomBannedMemberListViewState.kt | 1 + vector/src/main/res/values/strings.xml | 1 + 7 files changed, 64 insertions(+), 28 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f5d6fca073..9103acaa60 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ Improvements 🙌: - Small optimisation of scrolling experience in timeline (#2114) - Allow user to reset cross signing if he has no way to recover (#2052) - Create home shortcut for any room (#1525) - - Filter room member by name (#2184) + - Filter room member (and banned users) by name (#2184) Bugfix 🐛: - Improve support for image/audio/video/file selection with intent changes (#1376) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberAction.kt index 9af554e883..67cacf4541 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberAction.kt @@ -22,4 +22,5 @@ import im.vector.app.core.platform.VectorViewModelAction sealed class RoomBannedListMemberAction : VectorViewModelAction { data class QueryInfo(val roomMemberSummary: RoomMemberSummary) : RoomBannedListMemberAction() data class UnBanUser(val roomMemberSummary: RoomMemberSummary) : RoomBannedListMemberAction() + data class Filter(val filter: String) : RoomBannedListMemberAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberViewModel.kt index b65b3de807..d1acd80c25 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedListMemberViewModel.kt @@ -35,6 +35,7 @@ import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.unwrap import im.vector.app.R +import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.powerlevel.PowerLevelsObservableFactory @@ -90,6 +91,15 @@ class RoomBannedListMemberViewModel @AssistedInject constructor(@Assisted initia when (action) { is RoomBannedListMemberAction.QueryInfo -> onQueryBanInfo(action.roomMemberSummary) is RoomBannedListMemberAction.UnBanUser -> unBanUser(action.roomMemberSummary) + is RoomBannedListMemberAction.Filter -> handleFilter(action) + }.exhaustive + } + + private fun handleFilter(action: RoomBannedListMemberAction.Filter) { + setState { + copy( + filter = action.filter + ) } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListController.kt index a65a30441d..2a0c787a7a 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListController.kt @@ -17,8 +17,6 @@ package im.vector.app.features.roomprofile.banned import com.airbnb.epoxy.TypedEpoxyController -import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary -import org.matrix.android.sdk.api.util.toMatrixItem import im.vector.app.R import im.vector.app.core.epoxy.dividerItem import im.vector.app.core.epoxy.profiles.buildProfileSection @@ -28,11 +26,15 @@ import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.roomprofile.members.RoomMemberSummaryFilter +import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary +import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject class RoomBannedMemberListController @Inject constructor( private val avatarRenderer: AvatarRenderer, private val stringProvider: StringProvider, + private val roomMemberSummaryFilter: RoomMemberSummaryFilter, colorProvider: ColorProvider ) : TypedEpoxyController() { @@ -63,34 +65,37 @@ class RoomBannedMemberListController @Inject constructor( } else { buildProfileSection(quantityString) - bannedList.join( - each = { _, roomMember -> - val actionInProgress = data.onGoingModerationAction.contains(roomMember.userId) - profileMatrixItemWithProgress { - id(roomMember.userId) - matrixItem(roomMember.toMatrixItem()) - avatarRenderer(avatarRenderer) - apply { - if (actionInProgress) { - inProgress(true) - editable(false) - } else { - inProgress(false) - editable(true) - clickListener { _ -> - callback?.onUnbanClicked(roomMember) + roomMemberSummaryFilter.filter = data.filter + bannedList + .filter { roomMemberSummaryFilter.test(it) } + .join( + each = { _, roomMember -> + val actionInProgress = data.onGoingModerationAction.contains(roomMember.userId) + profileMatrixItemWithProgress { + id(roomMember.userId) + matrixItem(roomMember.toMatrixItem()) + avatarRenderer(avatarRenderer) + apply { + if (actionInProgress) { + inProgress(true) + editable(false) + } else { + inProgress(false) + editable(true) + clickListener { _ -> + callback?.onUnbanClicked(roomMember) + } + } } } + }, + between = { _, roomMemberBefore -> + dividerItem { + id("divider_${roomMemberBefore.userId}") + color(dividerColor) + } } - } - }, - between = { _, roomMemberBefore -> - dividerItem { - id("divider_${roomMemberBefore.userId}") - color(dividerColor) - } - } - ) + ) } } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt index 480deea6af..84eccccfae 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt @@ -19,6 +19,8 @@ package im.vector.app.features.roomprofile.banned import android.os.Bundle import android.view.View import androidx.appcompat.app.AlertDialog +import androidx.appcompat.widget.SearchView +import androidx.core.view.isVisible import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -53,6 +55,7 @@ class RoomBannedMemberListFragment @Inject constructor( super.onViewCreated(view, savedInstanceState) roomMemberListController.callback = this setupToolbar(roomSettingsToolbar) + setupSearchView() recyclerView.configureWith(roomMemberListController, hasFixedSize = true) viewModel.observeViewEvents { @@ -84,6 +87,21 @@ class RoomBannedMemberListFragment @Inject constructor( super.onDestroyView() } + private fun setupSearchView() { + searchViewAppBarLayout.isVisible = true + searchView.queryHint = getString(R.string.search_banned_user_hint) + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return true + } + + override fun onQueryTextChange(newText: String): Boolean { + viewModel.handle(RoomBannedListMemberAction.Filter(newText)) + return true + } + }) + } + override fun invalidate() = withState(viewModel) { viewState -> roomMemberListController.setData(viewState) renderRoomSummary(viewState) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt index ee8e534b1f..6d8bb2f42a 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt @@ -27,6 +27,7 @@ data class RoomBannedMemberListViewState( val roomId: String, val roomSummary: Async = Uninitialized, val bannedMemberSummaries: Async> = Uninitialized, + val filter: String = "", val onGoingModerationAction: List = emptyList(), val canUserBan: Boolean = false ) : MvRxState { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 9310af7577..9099c276e8 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -623,6 +623,7 @@ Search Filter room members + Filter banned users No results ROOMS MESSAGES From 8170f523e091ef4ca366e4e787a79fb9fa467a12 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 2 Oct 2020 23:29:48 +0200 Subject: [PATCH 45/47] Small improvement --- .../im/vector/app/features/home/room/list/RoomListNameFilter.kt | 2 +- .../app/features/roomprofile/members/RoomMemberListViewModel.kt | 2 +- .../app/features/roomprofile/members/RoomMemberSummaryFilter.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt index 4c4a9755d2..6e787b8b95 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt @@ -25,7 +25,7 @@ class RoomListNameFilter @Inject constructor() : Predicate { var filter: String = "" override fun test(roomSummary: RoomSummary): Boolean { - if (filter.isBlank()) { + if (filter.isEmpty()) { // No filter return true } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt index 60cb5867a7..9e402c675b 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt @@ -203,7 +203,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState } } - private fun handleFilterMemberList(action: RoomMemberListAction.FilterMemberList) = withState { + private fun handleFilterMemberList(action: RoomMemberListAction.FilterMemberList) { setState { copy( filter = action.searchTerm diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt index 813679fef3..e2cc3f7b99 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt @@ -25,7 +25,7 @@ class RoomMemberSummaryFilter @Inject constructor() : Predicate Date: Sun, 4 Oct 2020 12:43:26 +1300 Subject: [PATCH 46/47] Replace "him" with "them" in report interface All genders can spam a chatroom :) --- vector/src/main/res/values/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 9310af7577..c025054f98 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1851,11 +1851,11 @@ "IGNORE USER" "Content reported" - "This content was reported.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + "This content was reported.\n\nIf you don't want to see any more content from this user, you can ignore them to hide their messages." "Reported as spam" - "This content was reported as spam.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + "This content was reported as spam.\n\nIf you don't want to see any more content from this user, you can ignore them to hide their messages." "Reported as inappropriate" - "This content was reported as inappropriate.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + "This content was reported as inappropriate.\n\nIf you don't want to see any more content from this user, you can ignore them to hide their messages." Element needs permission to save your E2E keys on disk.\n\nPlease allow access on the next pop-up to be able to export your keys manually. From b2030930739b839b8d5dc483d05e95537b7f2ba0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Sun, 4 Oct 2020 11:17:57 +0200 Subject: [PATCH 47/47] Use an extra container for the margin to be taken into account by the layout_scrollFlags --- .../layout/fragment_room_setting_generic.xml | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/vector/src/main/res/layout/fragment_room_setting_generic.xml b/vector/src/main/res/layout/fragment_room_setting_generic.xml index 4ab6d2c7df..07744436ea 100644 --- a/vector/src/main/res/layout/fragment_room_setting_generic.xml +++ b/vector/src/main/res/layout/fragment_room_setting_generic.xml @@ -78,17 +78,24 @@ android:visibility="gone" tools:visibility="visible"> - + + app:layout_scrollFlags="scroll|enterAlways|snap"> + + + +