diff --git a/CHANGES.md b/CHANGES.md index d18a18e1c3..05ed55eb47 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,6 +20,7 @@ Bugfix 🐛: - Fix cancellation of sending event (#2438) - 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) - No known servers error is given when joining rooms on new Gitter bridge (#2516) - Show preview when sending attachment from the keyboard (#2440) - Do not compress GIFs (#1616, #1254) 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..18faa6a452 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/EventTypeFilter.kt @@ -0,0 +1,29 @@ +/* + * 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.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..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.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 3dcc5e21b1..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.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 3317612a6c..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 @@ -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()) { @@ -35,7 +40,7 @@ class TimelineSettingsFactory @Inject constructor(private val userPreferencesPro filterTypes = false), buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) } else { - val allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES.filterDisplayableTypes() + val allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES.createAllowedEventTypeFilters() TimelineSettings( initialSize = 30, filters = TimelineEventFilters( @@ -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.createAllowedEventTypeFilters(): List { + return map { + EventTypeFilter( + eventType = it, + stateKey = if (it == EventType.STATE_ROOM_MEMBER && userPreferencesProvider.shouldShowRoomMemberStateEvents()) session.myUserId else null + ) } } }