From abb9a0839afe29b355e606f53aff776b3b972c7a Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 15 Sep 2020 18:13:09 +0200 Subject: [PATCH 1/3] Room summary : change displayable events types --- .../room/summary/RoomSummaryConstants.kt | 33 ++++++++++++++ .../room/timeline/TimelineEventFilters.kt | 40 +++++++++++++++++ .../session/room/timeline/TimelineSettings.kt | 20 +-------- .../query/TimelineEventEntityQueries.kt | 41 ++++++++++++------ .../room/summary/RoomSummaryEventsHelper.kt | 43 +++++++++++++++++++ .../room/summary/RoomSummaryUpdater.kt | 35 +++------------ .../session/room/timeline/DefaultTimeline.kt | 26 +++-------- .../timeline/TimelineHiddenReadReceipts.kt | 10 ++--- .../room/timeline/TokenChunkEventPersistor.kt | 21 ++------- vector/build.gradle | 2 +- .../home/room/detail/RoomDetailViewModel.kt | 29 +++++++------ 11 files changed, 183 insertions(+), 117 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt new file mode 100644 index 0000000000..2b0132817d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt @@ -0,0 +1,33 @@ +/* + * 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.summary + +import org.matrix.android.sdk.api.session.events.model.EventType + +object RoomSummaryConstants { + + val PREVIEWABLE_TYPES = listOf( + // TODO filter message type (KEY_VERIFICATION_READY, etc.) + EventType.MESSAGE, + EventType.CALL_INVITE, + EventType.CALL_HANGUP, + EventType.CALL_ANSWER, + EventType.ENCRYPTED, + EventType.STICKER, + EventType.REACTION + ) +} 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 new file mode 100644 index 0000000000..eccc46b5d8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt @@ -0,0 +1,40 @@ +/* + * 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 TimelineEventFilters( + /** + * A flag to filter edit events + */ + val filterEdits: Boolean = false, + /** + * A flag to filter redacted events + */ + val filterRedacted: Boolean = false, + /** + * A flag to filter useless events, such as membership events without any change + */ + val filterUseless: Boolean = false, + /** + * A flag to filter by types. It should be used with [allowedTypes] field + */ + val filterTypes: Boolean = false, + /** + * If [filterTypes] is true, the list of types allowed by the list. + */ + val allowedTypes: List = emptyList() +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt index 4f915cb907..ab98208eed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt @@ -26,25 +26,9 @@ data class TimelineSettings( */ val initialSize: Int, /** - * A flag to filter edit events + * Filters for timeline event */ - val filterEdits: Boolean = false, - /** - * A flag to filter redacted events - */ - val filterRedacted: Boolean = false, - /** - * A flag to filter useless events, such as membership events without any change - */ - val filterUseless: Boolean = false, - /** - * A flag to filter by types. It should be used with [allowedTypes] field - */ - val filterTypes: Boolean = false, - /** - * If [filterTypes] is true, the list of types allowed by the list. - */ - val allowedTypes: List = emptyList(), + val filters: TimelineEventFilters = TimelineEventFilters(), /** * If true, will build read receipts for each event. */ 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 83075a192c..d49b64c432 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 @@ -17,17 +17,18 @@ package org.matrix.android.sdk.internal.database.query -import org.matrix.android.sdk.api.session.room.send.SendState -import org.matrix.android.sdk.internal.database.model.ChunkEntity -import org.matrix.android.sdk.internal.database.model.RoomEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import io.realm.Realm import io.realm.RealmList import io.realm.RealmQuery import io.realm.RealmResults import io.realm.Sort import io.realm.kotlin.where +import org.matrix.android.sdk.api.session.room.send.SendState +import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters +import org.matrix.android.sdk.internal.database.model.ChunkEntity +import org.matrix.android.sdk.internal.database.model.RoomEntity +import org.matrix.android.sdk.internal.database.model.TimelineEventEntity +import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields internal fun TimelineEventEntity.Companion.where(realm: Realm, roomId: String, eventId: String): RealmQuery { return realm.where() @@ -56,16 +57,10 @@ internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent(realm: internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, roomId: String, includesSending: Boolean, - filterContentRelation: Boolean = false, - filterTypes: List = emptyList()): TimelineEventEntity? { + filters: TimelineEventFilters = TimelineEventFilters()): TimelineEventEntity? { val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null - val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterTypes(filterTypes) - val liveEvents = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents?.where()?.filterTypes(filterTypes) - if (filterContentRelation) { - liveEvents - ?.not()?.like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT) - ?.not()?.like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE) - } + val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterEvents(filters) + val liveEvents = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents?.where()?.filterEvents(filters) val query = if (includesSending && sendingTimelineEvents.findAll().isNotEmpty()) { sendingTimelineEvents } else { @@ -76,6 +71,24 @@ internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, ?.findFirst() } +internal fun RealmQuery.filterEvents(filters: TimelineEventFilters): RealmQuery { + if (filters.filterTypes) { + `in`(TimelineEventEntityFields.ROOT.TYPE, filters.allowedTypes.toTypedArray()) + } + if (filters.filterUseless) { + not() + .equalTo(TimelineEventEntityFields.ROOT.IS_USELESS, true) + } + if (filters.filterEdits) { + not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT) + not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE) + } + if (filters.filterRedacted) { + not().like(TimelineEventEntityFields.ROOT.UNSIGNED_DATA, TimelineEventFilter.Unsigned.REDACTED) + } + return this +} + internal fun RealmQuery.filterTypes(filterTypes: List): RealmQuery { return if (filterTypes.isEmpty()) { this 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 new file mode 100644 index 0000000000..dd71bff436 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryEventsHelper.kt @@ -0,0 +1,43 @@ +/* + * 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.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.TimelineEventFilters +import org.matrix.android.sdk.internal.database.model.TimelineEventEntity +import org.matrix.android.sdk.internal.database.query.latestEvent + +internal object RoomSummaryEventsHelper { + + private val previewFilters = TimelineEventFilters( + filterTypes = true, + allowedTypes = RoomSummaryConstants.PREVIEWABLE_TYPES, + filterUseless = true, + filterRedacted = false, + filterEdits = true + ) + + fun getLatestPreviewableEvent(realm: Realm, roomId: String): TimelineEventEntity? { + return TimelineEventEntity.latestEvent( + realm = realm, + roomId = roomId, + includesSending = true, + filters = previewFilters + ) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 99671c232a..0aac30654a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.session.room.summary import dagger.Lazy +import io.realm.Realm +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel @@ -40,7 +42,6 @@ import org.matrix.android.sdk.internal.database.query.findAllInRoomWithSendState import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.getOrNull import org.matrix.android.sdk.internal.database.query.isEventRead -import org.matrix.android.sdk.internal.database.query.latestEvent import org.matrix.android.sdk.internal.database.query.whereType import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.room.RoomAvatarResolver @@ -49,8 +50,6 @@ import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.room.timeline.TimelineEventDecryptor import org.matrix.android.sdk.internal.session.sync.model.RoomSyncSummary import org.matrix.android.sdk.internal.session.sync.model.RoomSyncUnreadNotifications -import io.realm.Realm -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject @@ -61,28 +60,6 @@ internal class RoomSummaryUpdater @Inject constructor( private val timelineEventDecryptor: Lazy, private val eventBus: EventBus) { - companion object { - // TODO: maybe allow user of SDK to give that list - val PREVIEWABLE_TYPES = listOf( - // TODO filter message type (KEY_VERIFICATION_READY, etc.) - EventType.MESSAGE, - EventType.STATE_ROOM_NAME, - EventType.STATE_ROOM_TOPIC, - EventType.STATE_ROOM_AVATAR, - EventType.STATE_ROOM_MEMBER, - EventType.STATE_ROOM_HISTORY_VISIBILITY, - EventType.CALL_INVITE, - EventType.CALL_HANGUP, - EventType.CALL_ANSWER, - EventType.ENCRYPTED, - EventType.STATE_ROOM_ENCRYPTION, - EventType.STATE_ROOM_THIRD_PARTY_INVITE, - EventType.STICKER, - EventType.REACTION, - EventType.STATE_ROOM_CREATE - ) - } - fun update(realm: Realm, roomId: String, membership: Membership? = null, @@ -110,9 +87,6 @@ internal class RoomSummaryUpdater @Inject constructor( roomSummaryEntity.membership = membership } - val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, - filterTypes = PREVIEWABLE_TYPES, filterContentRelation = true) - val lastNameEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_NAME, stateKey = "")?.root val lastTopicEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_TOPIC, stateKey = "")?.root val lastCanonicalAliasEvent = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root @@ -123,6 +97,8 @@ internal class RoomSummaryUpdater @Inject constructor( .contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"") .findFirst() + val latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) + roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0 // avoid this call if we are sure there are unread events || !isEventRead(realm.configuration, userId, roomId, latestPreviewableEvent?.eventId) @@ -178,8 +154,7 @@ internal class RoomSummaryUpdater @Inject constructor( fun updateSendingInformation(realm: Realm, roomId: String) { val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId) roomSummaryEntity.updateHasFailedSending() - roomSummaryEntity.latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, - filterTypes = PREVIEWABLE_TYPES, filterContentRelation = true) + roomSummaryEntity.latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } fun updateShieldTrust(realm: Realm, 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 52651af881..2dead1d9cc 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 @@ -46,7 +46,7 @@ import org.matrix.android.sdk.internal.database.model.ChunkEntityFields import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields -import org.matrix.android.sdk.internal.database.query.TimelineEventFilter +import org.matrix.android.sdk.internal.database.query.filterEvents import org.matrix.android.sdk.internal.database.query.findAllInRoomWithSendStates import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.whereRoomId @@ -184,7 +184,7 @@ internal class DefaultTimeline( } private fun TimelineSettings.shouldHandleHiddenReadReceipts(): Boolean { - return buildReadReceipts && (filterEdits || filterTypes) + return buildReadReceipts && (filters.filterEdits || filters.filterTypes) } override fun dispose() { @@ -759,29 +759,15 @@ internal class DefaultTimeline( } private fun RealmQuery.filterEventsWithSettings(): RealmQuery { - if (settings.filterTypes) { - `in`(TimelineEventEntityFields.ROOT.TYPE, settings.allowedTypes.toTypedArray()) - } - if (settings.filterUseless) { - not() - .equalTo(TimelineEventEntityFields.ROOT.IS_USELESS, true) - } - if (settings.filterEdits) { - not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT) - not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE) - } - if (settings.filterRedacted) { - not().like(TimelineEventEntityFields.ROOT.UNSIGNED_DATA, TimelineEventFilter.Unsigned.REDACTED) - } - return this + return filterEvents(settings.filters) } private fun List.filterEventsWithSettings(): List { return filter { - val filterType = !settings.filterTypes || settings.allowedTypes.contains(it.root.type) + val filterType = !settings.filters.filterTypes || settings.filters.allowedTypes.contains(it.root.type) if (!filterType) return@filter false - val filterEdits = if (settings.filterEdits && it.root.type == EventType.MESSAGE) { + val filterEdits = if (settings.filters.filterEdits && it.root.type == EventType.MESSAGE) { val messageContent = it.root.content.toModel() messageContent?.relatesTo?.type != RelationType.REPLACE && messageContent?.relatesTo?.type != RelationType.RESPONSE } else { @@ -789,7 +775,7 @@ internal class DefaultTimeline( } if (!filterEdits) return@filter false - val filterRedacted = !settings.filterRedacted || it.root.isRedacted() + val filterRedacted = !settings.filters.filterRedacted || it.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 426daa4b57..276e49fbdf 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,23 +151,23 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu private fun RealmQuery.filterReceiptsWithSettings(): RealmQuery { beginGroup() var needOr = false - if (settings.filterTypes) { - not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", settings.allowedTypes.toTypedArray()) + if (settings.filters.filterTypes) { + not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", settings.filters.allowedTypes.toTypedArray()) needOr = true } - if (settings.filterUseless) { + if (settings.filters.filterUseless) { if (needOr) or() equalTo("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.IS_USELESS}", true) needOr = true } - if (settings.filterEdits) { + if (settings.filters.filterEdits) { if (needOr) or() like("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.CONTENT}", TimelineEventFilter.Content.EDIT) or() like("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.CONTENT}", TimelineEventFilter.Content.RESPONSE) needOr = true } - if (settings.filterRedacted) { + if (settings.filters.filterRedacted) { if (needOr) or() like("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.UNSIGNED_DATA}", TimelineEventFilter.Unsigned.REDACTED) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index da4eebe142..1fefdf9b50 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.timeline import com.zhuinden.monarchy.Monarchy +import io.realm.Realm import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomMemberContent @@ -32,19 +33,16 @@ import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.EventInsertType import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.find import org.matrix.android.sdk.internal.database.query.findAllIncludingEvents import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom import org.matrix.android.sdk.internal.database.query.getOrCreate -import org.matrix.android.sdk.internal.database.query.latestEvent import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase -import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater +import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryEventsHelper import org.matrix.android.sdk.internal.util.awaitTransaction -import io.realm.Realm import timber.log.Timber import javax.inject.Inject @@ -177,12 +175,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri currentChunk.isLastForward = true currentLastForwardChunk?.deleteOnCascade() RoomSummaryEntity.where(realm, roomId).findFirst()?.apply { - latestPreviewableEvent = TimelineEventEntity.latestEvent( - realm, - roomId, - includesSending = true, - filterTypes = RoomSummaryUpdater.PREVIEWABLE_TYPES - ) + latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } } } else { @@ -249,13 +242,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri val shouldUpdateSummary = roomSummaryEntity.latestPreviewableEvent == null || (chunksToDelete.isNotEmpty() && currentChunk.isLastForward && direction == PaginationDirection.FORWARDS) if (shouldUpdateSummary) { - val latestPreviewableEvent = TimelineEventEntity.latestEvent( - realm, - roomId, - includesSending = true, - filterTypes = RoomSummaryUpdater.PREVIEWABLE_TYPES - ) - roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent + roomSummaryEntity.latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } if (currentChunk.isValid) { RoomEntity.where(realm, roomId).findFirst()?.addOrUpdate(currentChunk) diff --git a/vector/build.gradle b/vector/build.gradle index e0f401aaf6..81864216b7 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -41,7 +41,7 @@ def getVersionCode() { if (gitBranchName() == "develop") { return generateVersionCodeFromTimestamp() } else { - return generateVersionCodeFromVersionName() + return generateVersionCodeFromTimestamp() } } 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 a77d50d767..aa628bee5b 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 @@ -62,8 +62,8 @@ import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.EventType -import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.LocalEcho +import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isTextMessage import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel @@ -86,6 +86,7 @@ import org.matrix.android.sdk.api.session.room.read.ReadService import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent import org.matrix.android.sdk.api.session.widgets.model.Widget @@ -122,19 +123,23 @@ class RoomDetailViewModel @AssistedInject constructor( private val invisibleEventsObservable = BehaviorRelay.create() private val visibleEventsObservable = BehaviorRelay.create() private val timelineSettings = if (userPreferencesProvider.shouldShowHiddenEvents()) { - TimelineSettings(30, - filterEdits = false, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = false, - filterTypes = false, + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = false, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = false, + filterTypes = false), buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) } else { - TimelineSettings(30, - filterEdits = true, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = true, - filterTypes = true, - allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES, + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = true, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = true, + filterTypes = true, + allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES), buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) } From a1f98eb6bfded775a99c82061e25ebccc15281c1 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 16 Sep 2020 15:36:48 +0200 Subject: [PATCH 2/3] Allow to filter all room member state events in timeline --- vector/build.gradle | 2 +- .../core/resources/UserPreferencesProvider.kt | 5 ++ .../home/room/detail/RoomDetailViewModel.kt | 27 ++------- .../helper/TimelineSettingsFactory.kt | 59 +++++++++++++++++++ .../features/settings/VectorPreferences.kt | 11 ++++ vector/src/main/res/values/strings.xml | 2 + .../res/xml/vector_settings_preferences.xml | 6 ++ 7 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt diff --git a/vector/build.gradle b/vector/build.gradle index 81864216b7..e0f401aaf6 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -41,7 +41,7 @@ def getVersionCode() { if (gitBranchName() == "develop") { return generateVersionCodeFromTimestamp() } else { - return generateVersionCodeFromTimestamp() + return generateVersionCodeFromVersionName() } } diff --git a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt index 302e55d1e7..e49831b826 100644 --- a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt @@ -40,4 +40,9 @@ class UserPreferencesProvider @Inject constructor(private val vectorPreferences: fun neverShowLongClickOnRoomHelpAgain() { vectorPreferences.neverShowLongClickOnRoomHelpAgain() } + + fun shouldShowRoomMemberStateEvents(): Boolean { + return vectorPreferences.showRoomMemberStateEvents() + } + } 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 aa628bee5b..9e00afe48a 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 @@ -41,6 +41,7 @@ import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder import im.vector.app.features.home.room.detail.timeline.helper.TimelineDisplayableEvents +import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory import im.vector.app.features.home.room.typing.TypingHelper import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.settings.VectorLocale @@ -106,7 +107,6 @@ import java.util.concurrent.atomic.AtomicBoolean class RoomDetailViewModel @AssistedInject constructor( @Assisted private val initialState: RoomDetailViewState, - userPreferencesProvider: UserPreferencesProvider, private val vectorPreferences: VectorPreferences, private val stringProvider: StringProvider, private val rainbowGenerator: RainbowGenerator, @@ -115,34 +115,15 @@ class RoomDetailViewModel @AssistedInject constructor( private val stickerPickerActionHandler: StickerPickerActionHandler, private val roomSummaryHolder: RoomSummaryHolder, private val typingHelper: TypingHelper, - private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager + private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager, + timelineSettingsFactory: TimelineSettingsFactory ) : VectorViewModel(initialState), Timeline.Listener { private val room = session.getRoom(initialState.roomId)!! private val eventId = initialState.eventId private val invisibleEventsObservable = BehaviorRelay.create() private val visibleEventsObservable = BehaviorRelay.create() - private val timelineSettings = if (userPreferencesProvider.shouldShowHiddenEvents()) { - TimelineSettings( - initialSize = 30, - filters = TimelineEventFilters( - filterEdits = false, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = false, - filterTypes = false), - buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) - } else { - TimelineSettings( - initialSize = 30, - filters = TimelineEventFilters( - filterEdits = true, - filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), - filterUseless = true, - filterTypes = true, - allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES), - buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) - } - + private val timelineSettings = timelineSettingsFactory.create() private var timelineEvents = PublishRelay.create>() val timeline = room.createTimeline(eventId, timelineSettings) 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 new file mode 100644 index 0000000000..3317612a6c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineSettingsFactory.kt @@ -0,0 +1,59 @@ +/* + * 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.home.room.detail.timeline.helper + +import im.vector.app.core.resources.UserPreferencesProvider +import org.matrix.android.sdk.api.session.events.model.EventType +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) { + + fun create(): TimelineSettings { + return if (userPreferencesProvider.shouldShowHiddenEvents()) { + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = false, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = false, + filterTypes = false), + buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) + } else { + val allowedTypes = TimelineDisplayableEvents.DISPLAYABLE_TYPES.filterDisplayableTypes() + TimelineSettings( + initialSize = 30, + filters = TimelineEventFilters( + filterEdits = true, + filterRedacted = userPreferencesProvider.shouldShowRedactedMessages().not(), + filterUseless = true, + filterTypes = true, + allowedTypes = allowedTypes), + buildReadReceipts = userPreferencesProvider.shouldShowReadReceipts()) + } + } + + private fun List.filterDisplayableTypes(): List { + return filter { type -> + when (type) { + EventType.STATE_ROOM_MEMBER -> userPreferencesProvider.shouldShowRoomMemberStateEvents() + else -> true + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 7415b57310..9fc566aac4 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -93,6 +93,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { private const val SETTINGS_12_24_TIMESTAMPS_KEY = "SETTINGS_12_24_TIMESTAMPS_KEY" private const val SETTINGS_SHOW_READ_RECEIPTS_KEY = "SETTINGS_SHOW_READ_RECEIPTS_KEY" private const val SETTINGS_SHOW_REDACTED_KEY = "SETTINGS_SHOW_REDACTED_KEY" + private const val SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY = "SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY" private const val SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY = "SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY" private const val SETTINGS_SHOW_AVATAR_DISPLAY_NAME_CHANGES_MESSAGES_KEY = "SETTINGS_SHOW_AVATAR_DISPLAY_NAME_CHANGES_MESSAGES_KEY" private const val SETTINGS_VIBRATE_ON_MENTION_KEY = "SETTINGS_VIBRATE_ON_MENTION_KEY" @@ -195,6 +196,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { SETTINGS_ALWAYS_SHOW_TIMESTAMPS_KEY, SETTINGS_12_24_TIMESTAMPS_KEY, SETTINGS_SHOW_READ_RECEIPTS_KEY, + SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY, SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY, SETTINGS_SHOW_AVATAR_DISPLAY_NAME_CHANGES_MESSAGES_KEY, SETTINGS_MEDIA_SAVING_PERIOD_KEY, @@ -343,6 +345,15 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_12_24_TIMESTAMPS_KEY, false) } + /** + * Tells if all room member state events should be shown in the messages list. + * + * @return true all room member state events should be shown in the messages list. + */ + fun showRoomMemberStateEvents(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_SHOW_ROOM_MEMBER_STATE_EVENTS_KEY, true) + } + /** * Tells if the join and leave membership events should be shown in the messages list. * diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 1ed36e4228..3adb7d21e2 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -857,6 +857,8 @@ Show timestamps in 12-hour format Show read receipts Click on the read receipts for a detailed list. + Show room member state events + Includes invite/join/left/kick/ban events and avatar/display name changes. Show join and leave events Invites, kicks, and bans are unaffected. Show account events diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 668aa9aa2b..ba8ba0d64b 100644 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -76,6 +76,12 @@ android:summary="@string/settings_show_redacted_summary" android:title="@string/settings_show_redacted" /> + + Date: Wed, 16 Sep 2020 15:48:09 +0200 Subject: [PATCH 3/3] Clean files and update CHANGES --- CHANGES.md | 2 ++ .../room/timeline/TimelineHiddenReadReceipts.kt | 11 ++++++----- .../app/core/resources/UserPreferencesProvider.kt | 1 - .../features/home/room/detail/RoomDetailViewModel.kt | 4 ---- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d8556e16bc..2f20c8b7f6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,8 @@ Bugfix 🐛: - Speakerphone is not used for ringback tone (#1644, #1645) - Back camera preview is not mirrored anymore (#1776) - Various report of people that cannot play video (#2107) + - Rooms incorrectly marked as unread (#588) + - Allow users to show/hide room member state events (#1231) Translations 🗣: - 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 276e49fbdf..f2c520a50f 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 @@ -18,6 +18,10 @@ package org.matrix.android.sdk.internal.session.room.timeline import android.util.SparseArray +import io.realm.OrderedRealmCollectionChangeListener +import io.realm.Realm +import io.realm.RealmQuery +import io.realm.RealmResults import org.matrix.android.sdk.api.session.room.model.ReadReceipt import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.internal.database.mapper.ReadReceiptsSummaryMapper @@ -27,10 +31,6 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.TimelineEventFilter import org.matrix.android.sdk.internal.database.query.whereInRoom -import io.realm.OrderedRealmCollectionChangeListener -import io.realm.Realm -import io.realm.RealmQuery -import io.realm.RealmResults /** * This class is responsible for handling the read receipts for hidden events (check [TimelineSettings] to see filtering). @@ -152,7 +152,8 @@ internal class TimelineHiddenReadReceipts constructor(private val readReceiptsSu beginGroup() var needOr = false if (settings.filters.filterTypes) { - not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", settings.filters.allowedTypes.toTypedArray()) + val allowedTypes = settings.filters.allowedTypes.toTypedArray() + not().`in`("${ReadReceiptsSummaryEntityFields.TIMELINE_EVENT}.${TimelineEventEntityFields.ROOT.TYPE}", allowedTypes) needOr = true } if (settings.filters.filterUseless) { diff --git a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt index e49831b826..f7d7b3864e 100644 --- a/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/UserPreferencesProvider.kt @@ -44,5 +44,4 @@ class UserPreferencesProvider @Inject constructor(private val vectorPreferences: fun shouldShowRoomMemberStateEvents(): Boolean { return vectorPreferences.showRoomMemberStateEvents() } - } 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 9e00afe48a..8164750aa4 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 @@ -31,7 +31,6 @@ 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.core.resources.UserPreferencesProvider import im.vector.app.core.utils.subscribeLogError import im.vector.app.features.call.WebRtcPeerConnectionManager import im.vector.app.features.command.CommandParser @@ -40,7 +39,6 @@ import im.vector.app.features.crypto.verification.SupportedVerificationMethodsPr import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder -import im.vector.app.features.home.room.detail.timeline.helper.TimelineDisplayableEvents import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory import im.vector.app.features.home.room.typing.TypingHelper import im.vector.app.features.powerlevel.PowerLevelsObservableFactory @@ -87,8 +85,6 @@ import org.matrix.android.sdk.api.session.room.read.ReadService import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent -import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters -import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.WidgetType