mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Adding live summary entity into annotation entity
This commit is contained in:
parent
25ca50c7bd
commit
b788a82d0d
9 changed files with 122 additions and 90 deletions
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.matrix.android.sdk.api.session.room.model.livelocation
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.message.LocationInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent
|
||||
|
||||
/**
|
||||
* Aggregation info concerning a live location share.
|
||||
|
@ -26,7 +26,8 @@ data class LiveLocationAggregatedSummary(
|
|||
* Event id of the event that started the live.
|
||||
*/
|
||||
val eventId: String,
|
||||
val roomId: String,
|
||||
val isLive: Boolean,
|
||||
val endOfLiveTimestampAsMilliseconds: Long,
|
||||
val lastLocation: LocationInfo? = null
|
||||
val lastLocationContent: MessageLocationContent? = null,
|
||||
)
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.events.model.Content
|
|||
import org.matrix.android.sdk.api.session.room.model.message.LocationAsset
|
||||
import org.matrix.android.sdk.api.session.room.model.message.LocationAssetType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||
|
||||
|
@ -61,16 +60,6 @@ data class LiveLocationBeaconContent(
|
|||
*/
|
||||
@Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset(LocationAssetType.SELF),
|
||||
@Json(name = "m.asset") val locationAsset: LocationAsset? = null,
|
||||
|
||||
/**
|
||||
* Client side tracking of the last location
|
||||
*/
|
||||
var lastLocationContent: MessageLiveLocationContent? = null,
|
||||
|
||||
/**
|
||||
* Client side tracking of whether the beacon has timed out.
|
||||
*/
|
||||
var hasTimedOut: Boolean = false
|
||||
) : MessageContent {
|
||||
|
||||
fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.model
|
|||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationAggregatedSummaryEntity
|
||||
import timber.log.Timber
|
||||
|
||||
internal open class EventAnnotationsSummaryEntity(
|
||||
|
@ -27,7 +28,8 @@ internal open class EventAnnotationsSummaryEntity(
|
|||
var reactionsSummary: RealmList<ReactionAggregatedSummaryEntity> = RealmList(),
|
||||
var editSummary: EditAggregatedSummaryEntity? = null,
|
||||
var referencesSummaryEntity: ReferencesAggregatedSummaryEntity? = null,
|
||||
var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null
|
||||
var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null,
|
||||
var liveLocationAggregatedSummary: LiveLocationAggregatedSummaryEntity? = null,
|
||||
) : RealmObject() {
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.matrix.android.sdk.internal.database.model
|
||||
|
||||
import io.realm.annotations.RealmModule
|
||||
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationAggregatedSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
|
||||
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
|
||||
|
||||
|
@ -47,6 +48,7 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
|
|||
EditAggregatedSummaryEntity::class,
|
||||
EditionOfEvent::class,
|
||||
PollResponseAggregatedSummaryEntity::class,
|
||||
LiveLocationAggregatedSummaryEntity::class,
|
||||
ReferencesAggregatedSummaryEntity::class,
|
||||
PushRulesEntity::class,
|
||||
PushRuleEntity::class,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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.database.query
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationAggregatedSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationAggregatedSummaryEntityFields
|
||||
|
||||
internal fun LiveLocationAggregatedSummaryEntity.Companion.where(realm: Realm, roomId: String, eventId: String): RealmQuery<LiveLocationAggregatedSummaryEntity> {
|
||||
return realm.where<LiveLocationAggregatedSummaryEntity>()
|
||||
.equalTo(LiveLocationAggregatedSummaryEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(LiveLocationAggregatedSummaryEntityFields.EVENT_ID, eventId)
|
||||
}
|
||||
|
||||
internal fun LiveLocationAggregatedSummaryEntity.Companion.create(realm: Realm, roomId: String, eventId: String): LiveLocationAggregatedSummaryEntity {
|
||||
val obj = realm.createObject(LiveLocationAggregatedSummaryEntity::class.java).apply {
|
||||
this.eventId = eventId
|
||||
this.roomId = roomId
|
||||
}
|
||||
val annotationSummary = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId = roomId, eventId = eventId)
|
||||
annotationSummary.liveLocationAggregatedSummary = obj
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
internal fun LiveLocationAggregatedSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String, eventId: String): LiveLocationAggregatedSummaryEntity {
|
||||
return LiveLocationAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
|
||||
?: LiveLocationAggregatedSummaryEntity.create(realm, roomId, eventId)
|
||||
}
|
|
@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
|||
import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent
|
||||
import org.matrix.android.sdk.api.session.room.model.VoteInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.VoteSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
||||
|
@ -91,7 +92,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
// EventType.KEY_VERIFICATION_READY,
|
||||
EventType.KEY_VERIFICATION_KEY,
|
||||
EventType.ENCRYPTED
|
||||
) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + EventType.BEACON_LOCATION_DATA
|
||||
) + EventType.POLL_START + EventType.POLL_RESPONSE + EventType.POLL_END + EventType.STATE_ROOM_BEACON_INFO + EventType.BEACON_LOCATION_DATA
|
||||
|
||||
override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean {
|
||||
return allowedTypes.contains(eventType)
|
||||
|
@ -106,12 +107,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
}
|
||||
val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
|
||||
when (event.type) {
|
||||
EventType.REACTION -> {
|
||||
EventType.REACTION -> {
|
||||
// we got a reaction!!
|
||||
Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}")
|
||||
handleReaction(realm, event, roomId, isLocalEcho)
|
||||
}
|
||||
EventType.MESSAGE -> {
|
||||
EventType.MESSAGE -> {
|
||||
if (event.unsignedData?.relations?.annotations != null) {
|
||||
Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}")
|
||||
handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations)
|
||||
|
@ -137,7 +138,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
EventType.KEY_VERIFICATION_START,
|
||||
EventType.KEY_VERIFICATION_MAC,
|
||||
EventType.KEY_VERIFICATION_READY,
|
||||
EventType.KEY_VERIFICATION_KEY -> {
|
||||
EventType.KEY_VERIFICATION_KEY -> {
|
||||
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
||||
event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
|
||||
if (it.type == RelationType.REFERENCE && it.eventId != null) {
|
||||
|
@ -146,7 +147,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
EventType.ENCRYPTED -> {
|
||||
EventType.ENCRYPTED -> {
|
||||
// Relation type is in clear
|
||||
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()
|
||||
if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE ||
|
||||
|
@ -172,23 +173,28 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
EventType.KEY_VERIFICATION_START,
|
||||
EventType.KEY_VERIFICATION_MAC,
|
||||
EventType.KEY_VERIFICATION_READY,
|
||||
EventType.KEY_VERIFICATION_KEY -> {
|
||||
EventType.KEY_VERIFICATION_KEY -> {
|
||||
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
||||
encryptedEventContent.relatesTo.eventId?.let {
|
||||
handleVerification(realm, event, roomId, isLocalEcho, it)
|
||||
}
|
||||
}
|
||||
in EventType.POLL_RESPONSE -> {
|
||||
in EventType.POLL_RESPONSE -> {
|
||||
event.getClearContent().toModel<MessagePollResponseContent>(catchError = true)?.let {
|
||||
handleResponse(realm, event, it, roomId, isLocalEcho, event.getRelationContent()?.eventId)
|
||||
}
|
||||
}
|
||||
in EventType.POLL_END -> {
|
||||
in EventType.POLL_END -> {
|
||||
event.content.toModel<MessageEndPollContent>(catchError = true)?.let {
|
||||
handleEndPoll(realm, event, it, roomId, isLocalEcho)
|
||||
}
|
||||
}
|
||||
in EventType.BEACON_LOCATION_DATA -> {
|
||||
in EventType.STATE_ROOM_BEACON_INFO -> {
|
||||
event.content.toModel<LiveLocationBeaconContent>(catchError = true)?.let {
|
||||
liveLocationAggregationProcessor.handleBeaconInfo(realm, event, it, roomId, isLocalEcho)
|
||||
}
|
||||
}
|
||||
in EventType.BEACON_LOCATION_DATA -> {
|
||||
event.content.toModel<MessageLiveLocationContent>(catchError = true)?.let {
|
||||
liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho)
|
||||
}
|
||||
|
@ -213,7 +219,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
// }
|
||||
// }
|
||||
}
|
||||
EventType.REDACTION -> {
|
||||
EventType.REDACTION -> {
|
||||
val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() }
|
||||
?: return
|
||||
when (eventToPrune.type) {
|
||||
|
@ -233,7 +239,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
in EventType.POLL_START -> {
|
||||
in EventType.POLL_START -> {
|
||||
val content: MessagePollContent? = event.content.toModel()
|
||||
if (content?.relatesTo?.type == RelationType.REPLACE) {
|
||||
Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
|
||||
|
@ -241,22 +247,27 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
handleReplace(realm, event, content, roomId, isLocalEcho)
|
||||
}
|
||||
}
|
||||
in EventType.POLL_RESPONSE -> {
|
||||
in EventType.POLL_RESPONSE -> {
|
||||
event.content.toModel<MessagePollResponseContent>(catchError = true)?.let {
|
||||
handleResponse(realm, event, it, roomId, isLocalEcho)
|
||||
}
|
||||
}
|
||||
in EventType.POLL_END -> {
|
||||
in EventType.POLL_END -> {
|
||||
event.content.toModel<MessageEndPollContent>(catchError = true)?.let {
|
||||
handleEndPoll(realm, event, it, roomId, isLocalEcho)
|
||||
}
|
||||
}
|
||||
in EventType.BEACON_LOCATION_DATA -> {
|
||||
in EventType.STATE_ROOM_BEACON_INFO -> {
|
||||
event.content.toModel<LiveLocationBeaconContent>(catchError = true)?.let {
|
||||
liveLocationAggregationProcessor.handleBeaconInfo(realm, event, it, roomId, isLocalEcho)
|
||||
}
|
||||
}
|
||||
in EventType.BEACON_LOCATION_DATA -> {
|
||||
event.content.toModel<MessageLiveLocationContent>(catchError = true)?.let {
|
||||
liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho)
|
||||
}
|
||||
}
|
||||
else -> Timber.v("UnHandled event ${event.eventId}")
|
||||
else -> Timber.v("UnHandled event ${event.eventId}")
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
Timber.e(t, "## Should not happen ")
|
||||
|
@ -325,7 +336,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
totalVotes = 0,
|
||||
winnerVoteCount = 0,
|
||||
)
|
||||
.toContent())
|
||||
.toContent()
|
||||
)
|
||||
}
|
||||
|
||||
val txId = event.unsignedData?.transactionId
|
||||
|
@ -729,11 +741,13 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||
EventType.KEY_VERIFICATION_READY,
|
||||
EventType.KEY_VERIFICATION_KEY,
|
||||
EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING)
|
||||
EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(if (event.senderId == userId) {
|
||||
VerificationState.CANCELED_BY_ME
|
||||
} else {
|
||||
VerificationState.CANCELED_BY_OTHER
|
||||
})
|
||||
EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(
|
||||
if (event.senderId == userId) {
|
||||
VerificationState.CANCELED_BY_ME
|
||||
} else {
|
||||
VerificationState.CANCELED_BY_OTHER
|
||||
}
|
||||
)
|
||||
EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE)
|
||||
else -> VerificationState.REQUEST
|
||||
}
|
||||
|
|
|
@ -17,69 +17,35 @@
|
|||
package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
|
||||
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||
import org.matrix.android.sdk.internal.database.query.getOrNull
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor {
|
||||
|
||||
override fun handleLiveLocation(realm: Realm, event: Event, content: MessageLiveLocationContent, roomId: String, isLocalEcho: Boolean) {
|
||||
val locationSenderId = event.senderId ?: return
|
||||
override fun handleBeaconInfo(realm: Realm, event: Event, content: LiveLocationBeaconContent, roomId: String, isLocalEcho: Boolean) {
|
||||
//val locationSenderId = event.senderId ?: return
|
||||
|
||||
// We shouldn't process local echos
|
||||
if (isLocalEcho) {
|
||||
return
|
||||
}
|
||||
|
||||
// A beacon info state event has to be sent before sending location
|
||||
// TODO handle missing check of m_relatesTo field
|
||||
var beaconInfoEntity: CurrentStateEventEntity? = null
|
||||
val eventTypesIterator = EventType.STATE_ROOM_BEACON_INFO.iterator()
|
||||
while (beaconInfoEntity == null && eventTypesIterator.hasNext()) {
|
||||
beaconInfoEntity = CurrentStateEventEntity.getOrNull(realm, roomId, locationSenderId, eventTypesIterator.next())
|
||||
}
|
||||
|
||||
if (beaconInfoEntity == null) {
|
||||
Timber.v("## LIVE LOCATION. There is not any beacon info which should be emitted before sending location updates")
|
||||
return
|
||||
}
|
||||
val beaconInfoContent = ContentMapper.map(beaconInfoEntity.root?.content)?.toModel<LiveLocationBeaconContent>(catchError = true)
|
||||
if (beaconInfoContent == null) {
|
||||
Timber.v("## LIVE LOCATION. Beacon info content is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if live location is ended
|
||||
if (!beaconInfoContent.isLive.orFalse()) {
|
||||
Timber.v("## LIVE LOCATION. Beacon info is not live anymore")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if beacon info is outdated
|
||||
if (isBeaconInfoOutdated(beaconInfoContent, content)) {
|
||||
Timber.v("## LIVE LOCATION. Beacon info has timeout")
|
||||
beaconInfoContent.hasTimedOut = true
|
||||
} else {
|
||||
beaconInfoContent.lastLocationContent = content
|
||||
}
|
||||
|
||||
beaconInfoEntity.root?.content = ContentMapper.map(beaconInfoContent.toContent())
|
||||
// TODO if live field is true, get eventId else get get replace eventId
|
||||
// TODO getOrCreate existing aggregated summary
|
||||
// TODO update the endOfLiveTimestamp and live fields
|
||||
}
|
||||
|
||||
private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent,
|
||||
liveLocationContent: MessageLiveLocationContent): Boolean {
|
||||
val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0
|
||||
val liveLocationEventTime = liveLocationContent.getBestTimestampAsMilliseconds() ?: 0
|
||||
val timeout = beaconInfoContent.timeout ?: 0
|
||||
return liveLocationEventTime - beaconInfoStartTime > timeout
|
||||
override fun handleLiveLocation(realm: Realm, event: Event, content: MessageLiveLocationContent, roomId: String, isLocalEcho: Boolean) {
|
||||
//val locationSenderId = event.senderId ?: return
|
||||
|
||||
// We shouldn't process local echos
|
||||
if (isLocalEcho) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO getOrCreate existing aggregated summary
|
||||
// TODO add location content only if more recent than the current one if any
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,23 @@ package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
|
|||
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
||||
|
||||
internal interface LiveLocationAggregationProcessor {
|
||||
fun handleLiveLocation(realm: Realm,
|
||||
event: Event,
|
||||
content: MessageLiveLocationContent,
|
||||
roomId: String,
|
||||
isLocalEcho: Boolean)
|
||||
fun handleBeaconInfo(
|
||||
realm: Realm,
|
||||
event: Event,
|
||||
content: LiveLocationBeaconContent,
|
||||
roomId: String,
|
||||
isLocalEcho: Boolean,
|
||||
)
|
||||
|
||||
fun handleLiveLocation(
|
||||
realm: Realm,
|
||||
event: Event,
|
||||
content: MessageLiveLocationContent,
|
||||
roomId: String,
|
||||
isLocalEcho: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ class LiveLocationMessageItemFactory @Inject constructor(
|
|||
}
|
||||
|
||||
private fun isLiveRunning(liveLocationContent: LiveLocationBeaconContent): Boolean {
|
||||
return liveLocationContent.isLive.orFalse() && liveLocationContent.hasTimedOut.not()
|
||||
// TODO when we will use aggregatedSummary, check if the live has timed out as well
|
||||
return liveLocationContent.isLive.orFalse()
|
||||
}
|
||||
|
||||
private fun buildStartLiveItem(
|
||||
|
|
Loading…
Reference in a new issue