From 245fbe86d9c725f03a793df19d9a35d622108eed Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 6 Aug 2019 21:32:40 +0200 Subject: [PATCH 1/4] Get enum safe with realm entities --- .../internal/database/model/GroupEntity.kt | 14 +++++----- .../internal/database/model/RoomEntity.kt | 14 +++++----- .../database/model/RoomSummaryEntity.kt | 28 ++++++++++--------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt index 35733d5ffe..dea36343d5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt @@ -18,20 +18,20 @@ package im.vector.matrix.android.internal.database.model import im.vector.matrix.android.api.session.room.model.Membership import io.realm.RealmObject -import io.realm.annotations.Ignore import io.realm.annotations.PrimaryKey -import kotlin.properties.Delegates internal open class GroupEntity(@PrimaryKey var groupId: String = "" ) : RealmObject() { private var membershipStr: String = Membership.NONE.name - - @delegate:Ignore - var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue -> - membershipStr = newValue.name - } + var membership: Membership + get() { + return Membership.valueOf(membershipStr) + } + set(value) { + membershipStr = value.name + } companion object diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt index b9c110b59a..a9f91390be 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt @@ -19,9 +19,7 @@ package im.vector.matrix.android.internal.database.model import im.vector.matrix.android.api.session.room.model.Membership import io.realm.RealmList import io.realm.RealmObject -import io.realm.annotations.Ignore import io.realm.annotations.PrimaryKey -import kotlin.properties.Delegates internal open class RoomEntity(@PrimaryKey var roomId: String = "", var chunks: RealmList = RealmList(), @@ -31,11 +29,13 @@ internal open class RoomEntity(@PrimaryKey var roomId: String = "", ) : RealmObject() { private var membershipStr: String = Membership.NONE.name - - @delegate:Ignore - var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue -> - membershipStr = newValue.name - } + var membership: Membership + get() { + return Membership.valueOf(membershipStr) + } + set(value) { + membershipStr = value.name + } companion object } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt index 08c9eabc3f..6fe81f4cdd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt @@ -20,9 +20,7 @@ import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.VersioningState import io.realm.RealmList import io.realm.RealmObject -import io.realm.annotations.Ignore import io.realm.annotations.PrimaryKey -import kotlin.properties.Delegates internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", var displayName: String? = "", @@ -41,18 +39,22 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", ) : RealmObject() { private var membershipStr: String = Membership.NONE.name + var membership: Membership + get() { + return Membership.valueOf(membershipStr) + } + set(value) { + membershipStr = value.name + } + private var versioningStateStr: String = VersioningState.NONE.name - - - @delegate:Ignore - var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue -> - membershipStr = newValue.name - } - - @delegate:Ignore - var versioningState: VersioningState by Delegates.observable(VersioningState.valueOf(versioningStateStr)) { _, _, newValue -> - versioningStateStr = newValue.name - } + var versioningState: VersioningState + get() { + return VersioningState.valueOf(versioningStateStr) + } + set(value) { + versioningStateStr = value.name + } companion object From 585f0ba4b79a4a4931f2a660dde560055a69c9e0 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 6 Aug 2019 21:32:45 +0200 Subject: [PATCH 2/4] Add an identifier method on ChunkEntity --- .../matrix/android/internal/database/model/ChunkEntity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt index 77a97f725f..d8661984d7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt @@ -33,6 +33,8 @@ internal open class ChunkEntity(@Index var prevToken: String? = null, var forwardsStateIndex: Int? = null ) : RealmObject() { + fun identifier() = "${prevToken}_${nextToken}" + @LinkingObjects("chunks") val room: RealmResults? = null From 7f09e64d63d28411465d47ab7c33d91dba5a2a70 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 7 Aug 2019 09:59:37 +0200 Subject: [PATCH 3/4] Fix timeline forward loader showing when sending events --- .../session/room/timeline/DefaultTimeline.kt | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt index 4259505131..b2a5847205 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt @@ -278,30 +278,32 @@ internal class DefaultTimeline( // Private methods ***************************************************************************** private fun hasMoreInCache(direction: Timeline.Direction): Boolean { - val localRealm = Realm.getInstance(realmConfiguration) - val timelineEventEntity = buildEventQuery(localRealm).findFirst(direction) ?: return false - val hasMoreInCache = if (direction == Timeline.Direction.FORWARDS) { - val firstEvent = builtEvents.firstOrNull() ?: return true - firstEvent.displayIndex < timelineEventEntity.root!!.displayIndex - } else { - val lastEvent = builtEvents.lastOrNull() ?: return true - lastEvent.displayIndex > timelineEventEntity.root!!.displayIndex + return Realm.getInstance(realmConfiguration).use { localRealm -> + val timelineEventEntity = buildEventQuery(localRealm).findFirst(direction) + ?: return false + if (direction == Timeline.Direction.FORWARDS) { + if (findCurrentChunk(localRealm)?.isLastForward == true) { + return false + } + val firstEvent = builtEvents.firstOrNull() ?: return true + firstEvent.displayIndex < timelineEventEntity.root!!.displayIndex + } else { + val lastEvent = builtEvents.lastOrNull() ?: return true + lastEvent.displayIndex > timelineEventEntity.root!!.displayIndex + } } - localRealm.close() - return hasMoreInCache } private fun hasReachedEnd(direction: Timeline.Direction): Boolean { - val localRealm = Realm.getInstance(realmConfiguration) - val currentChunk = findCurrentChunk(localRealm) ?: return false - val hasReachedEnd = if (direction == Timeline.Direction.FORWARDS) { - currentChunk.isLastForward - } else { - val eventEntity = buildEventQuery(localRealm).findFirst(direction) - currentChunk.isLastBackward || eventEntity?.root?.type == EventType.STATE_ROOM_CREATE + return Realm.getInstance(realmConfiguration).use { localRealm -> + val currentChunk = findCurrentChunk(localRealm) ?: return false + if (direction == Timeline.Direction.FORWARDS) { + currentChunk.isLastForward + } else { + val eventEntity = buildEventQuery(localRealm).findFirst(direction) + currentChunk.isLastBackward || eventEntity?.root?.type == EventType.STATE_ROOM_CREATE + } } - localRealm.close() - return hasReachedEnd } From 0949d29f9cbdc8e7c0f7e3588c96e1ed17a5dc09 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 7 Aug 2019 10:54:54 +0200 Subject: [PATCH 4/4] Let TimelineEvent be queried by SendState --- .../api/session/room/send/SendState.kt | 20 +++--- .../query/TimelineEventEntityQueries.kt | 18 +++-- .../session/room/send/DefaultSendService.kt | 70 +++++++++---------- .../session/room/timeline/DefaultTimeline.kt | 20 ++---- 4 files changed, 67 insertions(+), 61 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt index e9f22da472..aaa7020be6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/send/SendState.kt @@ -16,6 +16,7 @@ package im.vector.matrix.android.api.session.room.send + enum class SendState { UNKNOWN, // the event has not been sent @@ -33,16 +34,19 @@ enum class SendState { // the event failed to be sent because some unknown devices have been found while encrypting it FAILED_UNKNOWN_DEVICES; - fun isSent(): Boolean { - return this == SENT || this == SYNCED + internal companion object { + val HAS_FAILED_STATES = listOf(UNDELIVERED, FAILED_UNKNOWN_DEVICES) + val IS_SENT_STATES = listOf(SENT, SYNCED) + val IS_SENDING_STATES = listOf(UNSENT, ENCRYPTING, SENDING) + val PENDING_STATES = IS_SENDING_STATES + HAS_FAILED_STATES } - fun hasFailed(): Boolean { - return this == UNDELIVERED || this == FAILED_UNKNOWN_DEVICES - } + fun isSent() = IS_SENT_STATES.contains(this) - fun isSending(): Boolean { - return this == UNSENT || this == ENCRYPTING || this == SENDING - } + fun hasFailed() = HAS_FAILED_STATES.contains(this) + + fun isSending() = IS_SENDING_STATES.contains(this) } + + diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt index 5a48e02223..182e58a3b5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt @@ -16,12 +16,10 @@ package im.vector.matrix.android.internal.database.query +import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.internal.database.model.* import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.* -import io.realm.Realm -import io.realm.RealmList -import io.realm.RealmQuery -import io.realm.Sort +import io.realm.* import io.realm.kotlin.where internal fun TimelineEventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery { @@ -114,3 +112,15 @@ internal fun RealmList.find(eventId: String): TimelineEvent .equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId) .findFirst() } + +internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(realm: Realm, + roomId: String, + sendStates: List) + : RealmResults { + + val sendStatesStr = sendStates.map { it.name }.toTypedArray() + return realm.where() + .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) + .`in`(TimelineEventEntityFields.ROOT.SEND_STATE_STR,sendStatesStr) + .findAll() +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt index 8b65be24b1..d822e94943 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt @@ -34,6 +34,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity +import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.session.content.UploadContentWorker import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon @@ -188,48 +189,47 @@ internal class DefaultSendService @Inject constructor(private val context: Conte override fun resendAllFailedMessages() { monarchy.writeAsync { realm -> - RoomEntity.where(realm, roomId).findFirst()?.let { room -> - room.sendingTimelineEvents.filter { - it.root?.sendState?.hasFailed() ?: false - }.sortedBy { it.root?.originServerTs ?: 0 }.forEach { timelineEventEntity -> - timelineEventEntity.root?.let { - val event = it.asDomain() - when (event.getClearType()) { - EventType.MESSAGE, - EventType.REDACTION, - EventType.REACTION -> { - val content = event.getClearContent().toModel() - if (content != null) { - when (content.type) { - MessageType.MSGTYPE_EMOTE, - MessageType.MSGTYPE_NOTICE, - MessageType.MSGTYPE_LOCATION, - MessageType.MSGTYPE_TEXT -> { - it.sendState = SendState.UNSENT - sendEvent(event) - } - MessageType.MSGTYPE_FILE, - MessageType.MSGTYPE_VIDEO, - MessageType.MSGTYPE_IMAGE, - MessageType.MSGTYPE_AUDIO -> { - //need to resend the attachement - } - else -> { - Timber.e("Cannot resend message ${event.type} / ${content.type}") - } + TimelineEventEntity + .findAllInRoomWithSendStates(realm, roomId, SendState.HAS_FAILED_STATES) + .sortedBy { it.root?.originServerTs ?: 0 } + .forEach { timelineEventEntity -> + timelineEventEntity.root?.let { + val event = it.asDomain() + when (event.getClearType()) { + EventType.MESSAGE, + EventType.REDACTION, + EventType.REACTION -> { + val content = event.getClearContent().toModel() + if (content != null) { + when (content.type) { + MessageType.MSGTYPE_EMOTE, + MessageType.MSGTYPE_NOTICE, + MessageType.MSGTYPE_LOCATION, + MessageType.MSGTYPE_TEXT -> { + it.sendState = SendState.UNSENT + sendEvent(event) + } + MessageType.MSGTYPE_FILE, + MessageType.MSGTYPE_VIDEO, + MessageType.MSGTYPE_IMAGE, + MessageType.MSGTYPE_AUDIO -> { + //need to resend the attachement + } + else -> { + Timber.e("Cannot resend message ${event.type} / ${content.type}") + } + } + } else { + Timber.e("Unsupported message to resend ${event.type}") } - } else { + } + else -> { Timber.e("Unsupported message to resend ${event.type}") } } - else -> { - Timber.e("Unsupported message to resend ${event.type}") - } } } - } - } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt index b2a5847205..10f4874fbd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt @@ -19,16 +19,14 @@ package im.vector.matrix.android.internal.session.room.timeline import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.util.CancelableBag import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.* import im.vector.matrix.android.internal.database.model.EventEntity -import im.vector.matrix.android.internal.database.query.findIncludingEvent -import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom -import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.database.query.whereInRoom +import im.vector.matrix.android.internal.database.query.* import im.vector.matrix.android.internal.task.TaskConstraints import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith @@ -208,21 +206,15 @@ internal class DefaultTimeline( } override fun pendingEventCount(): Int { - var count = 0 - Realm.getInstance(realmConfiguration).use { - count = RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.count() ?: 0 + return Realm.getInstance(realmConfiguration).use { + RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.count() ?: 0 } - return count } override fun failedToDeliverEventCount(): Int { - var count = 0 - Realm.getInstance(realmConfiguration).use { - count = RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.filter { - it.root?.sendState?.hasFailed() ?: false - }?.count() ?: 0 + return Realm.getInstance(realmConfiguration).use { + TimelineEventEntity.findAllInRoomWithSendStates(it, roomId, SendState.HAS_FAILED_STATES).count() } - return count } override fun start() {