From a6724b5f75df3aa078e2f5bbc42d901a3febb76d Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 3 Dec 2020 16:10:50 +0300 Subject: [PATCH 1/4] EventTypeFilter implementation to allow hiding member events. --- .../session/room/timeline/EventTypeFilter.kt | 29 +++++++++++++++++++ .../room/timeline/TimelineEventFilters.kt | 2 +- .../query/TimelineEventEntityQueries.kt | 19 ++++++++++-- .../room/summary/RoomSummaryEventsHelper.kt | 3 +- .../session/room/timeline/DefaultTimeline.kt | 2 +- .../timeline/TimelineHiddenReadReceipts.kt | 2 +- .../helper/TimelineSettingsFactory.kt | 19 +++++++----- 7 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt new file mode 100644 index 0000000000..f2f6929fdd --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt @@ -0,0 +1,29 @@ +/* + * 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.api.session.room.timeline + +data class EventTypeFilter( + /** + * Allowed event type. + */ + val eventType: String, + /** + * Allowed state key. Set null if you want to allow all events, + * otherwise allowed events will be filtered according to the given stateKey. + */ + val stateKey: String? +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt index c751632286..4415c8e4b3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt @@ -36,5 +36,5 @@ data class TimelineEventFilters( /** * If [filterTypes] is true, the list of types allowed by the list. */ - val allowedTypes: List = emptyList() + val allowedTypes: List = emptyList() ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt index 41a13c785d..148232cf94 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt @@ -71,8 +71,23 @@ internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, } internal fun RealmQuery.filterEvents(filters: TimelineEventFilters): RealmQuery { - if (filters.filterTypes) { - `in`(TimelineEventEntityFields.ROOT.TYPE, filters.allowedTypes.toTypedArray()) + if (filters.filterTypes && filters.allowedTypes.isNotEmpty()) { + beginGroup() + filters.allowedTypes.forEachIndexed { index, filter -> + if (filter.stateKey == null) { + equalTo(TimelineEventEntityFields.ROOT.TYPE, filter.eventType) + } else { + beginGroup() + equalTo(TimelineEventEntityFields.ROOT.TYPE, filter.eventType) + and() + equalTo(TimelineEventEntityFields.ROOT.STATE_KEY, filter.stateKey) + endGroup() + } + if (index != filters.allowedTypes.size - 1) { + or() + } + } + endGroup() } if (filters.filterUseless) { not() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt index a3862b001b..7437a686da 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.summary import io.realm.Realm import org.matrix.android.sdk.api.session.room.summary.RoomSummaryConstants +import org.matrix.android.sdk.api.session.room.timeline.EventTypeFilter import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.query.latestEvent @@ -26,7 +27,7 @@ internal object RoomSummaryEventsHelper { private val previewFilters = TimelineEventFilters( filterTypes = true, - allowedTypes = RoomSummaryConstants.PREVIEWABLE_TYPES, + allowedTypes = RoomSummaryConstants.PREVIEWABLE_TYPES.map { EventTypeFilter(eventType = it, stateKey = null) }, filterUseless = true, filterRedacted = false, filterEdits = true diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index 995a21aa23..0dc0d33d38 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -785,7 +785,7 @@ internal class DefaultTimeline( private fun List.filterEventsWithSettings(): List { return filter { - val filterType = !settings.filters.filterTypes || settings.filters.allowedTypes.contains(it.root.type) + val filterType = !settings.filters.filterTypes || settings.filters.allowedTypes.map { it.eventType }.contains(it.root.type) if (!filterType) return@filter false val filterEdits = if (settings.filters.filterEdits && it.root.getClearType() == EventType.MESSAGE) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt index 3dcc5e21b1..6fe6013108 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt @@ -151,7 +151,7 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu beginGroup() var needOr = false if (settings.filters.filterTypes) { - val allowedTypes = settings.filters.allowedTypes.toTypedArray() + val allowedTypes = settings.filters.allowedTypes.map { it.eventType }.toTypedArray() not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", allowedTypes) needOr = true } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt index 3317612a6c..ff396646c0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt @@ -17,12 +17,17 @@ package im.vector.app.features.home.room.detail.timeline.helper import im.vector.app.core.resources.UserPreferencesProvider +import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.room.timeline.EventTypeFilter import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import javax.inject.Inject -class TimelineSettingsFactory @Inject constructor(private val userPreferencesProvider: UserPreferencesProvider) { +class TimelineSettingsFactory @Inject constructor( + private val userPreferencesProvider: UserPreferencesProvider, + private val session: Session +) { fun create(): TimelineSettings { return if (userPreferencesProvider.shouldShowHiddenEvents()) { @@ -48,12 +53,12 @@ class TimelineSettingsFactory @Inject constructor(private val userPreferencesPro } } - private fun List.filterDisplayableTypes(): List { - return filter { type -> - when (type) { - EventType.STATE_ROOM_MEMBER -> userPreferencesProvider.shouldShowRoomMemberStateEvents() - else -> true - } + private fun List.filterDisplayableTypes(): List { + return map { + EventTypeFilter( + eventType = it, + stateKey = if (it == EventType.STATE_ROOM_MEMBER && userPreferencesProvider.shouldShowRoomMemberStateEvents()) session.myUserId else null + ) } } } From 32b7cc64fb1c6915d645fba6d22d3d663494110f Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 3 Dec 2020 16:19:37 +0300 Subject: [PATCH 2/4] Changelog added. Fixes #2486 --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index f6f63db534..321bfd9bef 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ Improvements 🙌: Bugfix 🐛: - Double bottomsheet effect after verify with passphrase - EditText cursor jumps to the start while typing fast (#2469) + - UTD for events before invitation if member state events are hidden (#2486) Translations 🗣: - From 752bde413ddc223313ebd5156a3e56736c3121ec Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 10 Dec 2020 13:47:23 +0300 Subject: [PATCH 3/4] Fix copyright. --- .../android/sdk/api/session/room/timeline/EventTypeFilter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt index f2f6929fdd..18faa6a452 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 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. From 60aaa2a39c14311f6870e29c7ac4fec0d5a1dd92 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 11 Dec 2020 15:08:32 +0300 Subject: [PATCH 4/4] Code review fixes. --- .../session/room/timeline/DefaultTimeline.kt | 11 +++++----- .../timeline/TimelineHiddenReadReceipts.kt | 21 +++++++++++++++++-- .../helper/TimelineSettingsFactory.kt | 4 ++-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index 0dc0d33d38..86b0497bd0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -784,19 +784,20 @@ internal class DefaultTimeline( } private fun List.filterEventsWithSettings(): List { - return filter { - val filterType = !settings.filters.filterTypes || settings.filters.allowedTypes.map { it.eventType }.contains(it.root.type) + return filter { event -> + val filterType = !settings.filters.filterTypes + || settings.filters.allowedTypes.any { it.eventType == event.root.type && (it.stateKey == null || it.stateKey == event.root.senderId) } if (!filterType) return@filter false - val filterEdits = if (settings.filters.filterEdits && it.root.getClearType() == EventType.MESSAGE) { - val messageContent = it.root.getClearContent().toModel() + val filterEdits = if (settings.filters.filterEdits && event.root.getClearType() == EventType.MESSAGE) { + val messageContent = event.root.getClearContent().toModel() messageContent?.relatesTo?.type != RelationType.REPLACE && messageContent?.relatesTo?.type != RelationType.RESPONSE } else { true } if (!filterEdits) return@filter false - val filterRedacted = settings.filters.filterRedacted && it.root.isRedacted() + val filterRedacted = settings.filters.filterRedacted && event.root.isRedacted() !filterRedacted } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt index 6fe6013108..fa517bebf2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineHiddenReadReceipts.kt @@ -151,8 +151,25 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu beginGroup() var needOr = false if (settings.filters.filterTypes) { - val allowedTypes = settings.filters.allowedTypes.map { it.eventType }.toTypedArray() - not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", allowedTypes) + beginGroup() + // Events: A, B, C, D, (E and S1), F, G, (H and S1), I + // Allowed: A, B, C, (E and S1), G, (H and S2) + // Result: D, F, H, I + settings.filters.allowedTypes.forEachIndexed { index, filter -> + if (filter.stateKey == null) { + notEqualTo("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", filter.eventType) + } else { + beginGroup() + notEqualTo("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", filter.eventType) + or() + notEqualTo("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.STATE_KEY}", filter.stateKey) + endGroup() + } + if (index != settings.filters.allowedTypes.size - 1) { + and() + } + } + endGroup() needOr = true } if (settings.filters.filterUseless) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt index ff396646c0..1983b05ed3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt @@ -40,7 +40,7 @@ class TimelineSettingsFactory @Inject constructor( filterTypes = false), buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) } else { - val allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES.filterDisplayableTypes() + val allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES.createAllowedEventTypeFilters() TimelineSettings( initialSize = 30, filters = TimelineEventFilters( @@ -53,7 +53,7 @@ class TimelineSettingsFactory @Inject constructor( } } - private fun List.filterDisplayableTypes(): List { + private fun List.createAllowedEventTypeFilters(): List { return map { EventTypeFilter( eventType = it,