Merge pull request #5869 from vector-im/feature/mna/PSF-884-live-location-aggregation
[Live location sharing] Improve aggregation process of events
This commit is contained in:
commit
b5a0c944d1
1
changelog.d/5862.wip
Normal file
1
changelog.d/5862.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Live location sharing] Improve aggregation process of events
|
@ -15,9 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.matrix.android.sdk.api.session.room.model
|
package org.matrix.android.sdk.api.session.room.model
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
|
||||||
|
|
||||||
data class EventAnnotationsSummary(
|
data class EventAnnotationsSummary(
|
||||||
val reactionsSummary: List<ReactionAggregatedSummary> = emptyList(),
|
val reactionsSummary: List<ReactionAggregatedSummary> = emptyList(),
|
||||||
val editSummary: EditAggregatedSummary? = null,
|
val editSummary: EditAggregatedSummary? = null,
|
||||||
val pollResponseSummary: PollResponseAggregatedSummary? = null,
|
val pollResponseSummary: PollResponseAggregatedSummary? = null,
|
||||||
val referencesAggregatedSummary: ReferencesAggregatedSummary? = null
|
val referencesAggregatedSummary: ReferencesAggregatedSummary? = null,
|
||||||
|
val liveLocationShareAggregatedSummary: LiveLocationShareAggregatedSummary? = null,
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.model.livelocation
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregation info concerning a live location share.
|
||||||
|
*/
|
||||||
|
data class LiveLocationShareAggregatedSummary(
|
||||||
|
val isActive: Boolean?,
|
||||||
|
val endOfLiveTimestampMillis: Long?,
|
||||||
|
val lastLocationDataContent: MessageBeaconLocationDataContent?,
|
||||||
|
)
|
@ -14,25 +14,28 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.room.model.livelocation
|
package org.matrix.android.sdk.api.session.room.model.message
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import org.matrix.android.sdk.api.session.events.model.Content
|
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
|
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content of the state event of type
|
||||||
|
* [EventType.STATE_ROOM_BEACON_INFO][org.matrix.android.sdk.api.session.events.model.EventType.STATE_ROOM_BEACON_INFO]
|
||||||
|
*
|
||||||
|
* It contains general info related to a live location share.
|
||||||
|
* Locations are sent in a different message related to the state event.
|
||||||
|
* See [MessageBeaconLocationDataContent][org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent]
|
||||||
|
*/
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class LiveLocationBeaconContent(
|
data class MessageBeaconInfoContent(
|
||||||
/**
|
/**
|
||||||
* Local message type, not from server
|
* Local message type, not from server
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
override val msgType: String = MessageType.MSGTYPE_LIVE_LOCATION_STATE,
|
override val msgType: String = MessageType.MSGTYPE_BEACON_INFO,
|
||||||
|
|
||||||
@Json(name = "body") override val body: String = "",
|
@Json(name = "body") override val body: String = "",
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@ -54,26 +57,16 @@ data class LiveLocationBeaconContent(
|
|||||||
/**
|
/**
|
||||||
* Beacon creation timestamp.
|
* Beacon creation timestamp.
|
||||||
*/
|
*/
|
||||||
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null,
|
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
|
||||||
@Json(name = "m.ts") val timestampAsMilliseconds: Long? = null,
|
@Json(name = "m.ts") val timestampMillis: Long? = null,
|
||||||
/**
|
/**
|
||||||
* Live location asset type.
|
* Live location asset type.
|
||||||
*/
|
*/
|
||||||
@Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset(LocationAssetType.SELF),
|
@Json(name = "org.matrix.msc3488.asset") val unstableLocationAsset: LocationAsset = LocationAsset(LocationAssetType.SELF),
|
||||||
@Json(name = "m.asset") val locationAsset: LocationAsset? = null,
|
@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 {
|
) : MessageContent {
|
||||||
|
|
||||||
fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds
|
fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis
|
||||||
|
|
||||||
fun getBestLocationAsset() = locationAsset ?: unstableLocationAsset
|
fun getBestLocationAsset() = locationAsset ?: unstableLocationAsset
|
||||||
}
|
}
|
@ -21,13 +21,21 @@ import com.squareup.moshi.JsonClass
|
|||||||
import org.matrix.android.sdk.api.session.events.model.Content
|
import org.matrix.android.sdk.api.session.events.model.Content
|
||||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content of the state event of type
|
||||||
|
* [EventType.BEACON_LOCATION_DATA][org.matrix.android.sdk.api.session.events.model.EventType.BEACON_LOCATION_DATA]
|
||||||
|
*
|
||||||
|
* It contains location data related to a live location share.
|
||||||
|
* It is related to the state event that originally started the live.
|
||||||
|
* See [MessageBeaconInfoContent][org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent]
|
||||||
|
*/
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MessageLiveLocationContent(
|
data class MessageBeaconLocationDataContent(
|
||||||
/**
|
/**
|
||||||
* Local message type, not from server
|
* Local message type, not from server
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
override val msgType: String = MessageType.MSGTYPE_LIVE_LOCATION,
|
override val msgType: String = MessageType.MSGTYPE_BEACON_LOCATION_DATA,
|
||||||
|
|
||||||
@Json(name = "body") override val body: String = "",
|
@Json(name = "body") override val body: String = "",
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@ -42,11 +50,11 @@ data class MessageLiveLocationContent(
|
|||||||
/**
|
/**
|
||||||
* Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
|
* Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
|
||||||
*/
|
*/
|
||||||
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampAsMilliseconds: Long? = null,
|
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
|
||||||
@Json(name = "m.ts") val timestampAsMilliseconds: Long? = null
|
@Json(name = "m.ts") val timestampMillis: Long? = null
|
||||||
) : MessageContent {
|
) : MessageContent {
|
||||||
|
|
||||||
fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo
|
fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo
|
||||||
|
|
||||||
fun getBestTimestampAsMilliseconds() = timestampAsMilliseconds ?: unstableTimestampAsMilliseconds
|
fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis
|
||||||
}
|
}
|
@ -49,8 +49,8 @@ data class MessageLocationContent(
|
|||||||
/**
|
/**
|
||||||
* Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
|
* Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
|
||||||
*/
|
*/
|
||||||
@Json(name = "org.matrix.msc3488.ts") val unstableTs: Long? = null,
|
@Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
|
||||||
@Json(name = "m.ts") val ts: Long? = null,
|
@Json(name = "m.ts") val timestampMillis: Long? = null,
|
||||||
@Json(name = "org.matrix.msc1767.text") val unstableText: String? = null,
|
@Json(name = "org.matrix.msc1767.text") val unstableText: String? = null,
|
||||||
@Json(name = "m.text") val text: String? = null,
|
@Json(name = "m.text") val text: String? = null,
|
||||||
/**
|
/**
|
||||||
@ -66,7 +66,7 @@ data class MessageLocationContent(
|
|||||||
|
|
||||||
fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo
|
fun getBestLocationInfo() = locationInfo ?: unstableLocationInfo
|
||||||
|
|
||||||
fun getBestTs() = ts ?: unstableTs
|
fun getBestTimestampMillis() = timestampMillis ?: unstableTimestampMillis
|
||||||
|
|
||||||
fun getBestText() = text ?: unstableText
|
fun getBestText() = text ?: unstableText
|
||||||
|
|
||||||
|
@ -41,6 +41,6 @@ object MessageType {
|
|||||||
const val MSGTYPE_SNOWFALL = "io.element.effect.snowfall"
|
const val MSGTYPE_SNOWFALL = "io.element.effect.snowfall"
|
||||||
|
|
||||||
// Fake message types for live location events to be able to inherit them from MessageContent
|
// Fake message types for live location events to be able to inherit them from MessageContent
|
||||||
const val MSGTYPE_LIVE_LOCATION_STATE = "org.matrix.android.sdk.livelocation.state"
|
const val MSGTYPE_BEACON_INFO = "org.matrix.android.sdk.beacon.info"
|
||||||
const val MSGTYPE_LIVE_LOCATION = "org.matrix.android.sdk.livelocation"
|
const val MSGTYPE_BEACON_LOCATION_DATA = "org.matrix.android.sdk.beacon.location.data"
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.session.events.model.isSticker
|
|||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
|
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
|
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
|
||||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
|
||||||
@ -139,7 +139,7 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? {
|
|||||||
return when (root.getClearType()) {
|
return when (root.getClearType()) {
|
||||||
EventType.STICKER -> root.getClearContent().toModel<MessageStickerContent>()
|
EventType.STICKER -> root.getClearContent().toModel<MessageStickerContent>()
|
||||||
in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>()
|
in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>()
|
||||||
in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<LiveLocationBeaconContent>()
|
in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconInfoContent>()
|
||||||
else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
|
else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo023
|
|||||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo024
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo024
|
||||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo025
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo025
|
||||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo026
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo026
|
||||||
|
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo027
|
||||||
import org.matrix.android.sdk.internal.util.Normalizer
|
import org.matrix.android.sdk.internal.util.Normalizer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -58,7 +59,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||||||
override fun equals(other: Any?) = other is RealmSessionStoreMigration
|
override fun equals(other: Any?) = other is RealmSessionStoreMigration
|
||||||
override fun hashCode() = 1000
|
override fun hashCode() = 1000
|
||||||
|
|
||||||
val schemaVersion = 26L
|
val schemaVersion = 27L
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
|
Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
|
||||||
@ -89,5 +90,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||||||
if (oldVersion < 24) MigrateSessionTo024(realm).perform()
|
if (oldVersion < 24) MigrateSessionTo024(realm).perform()
|
||||||
if (oldVersion < 25) MigrateSessionTo025(realm).perform()
|
if (oldVersion < 25) MigrateSessionTo025(realm).perform()
|
||||||
if (oldVersion < 26) MigrateSessionTo026(realm).perform()
|
if (oldVersion < 26) MigrateSessionTo026(realm).perform()
|
||||||
|
if (oldVersion < 27) MigrateSessionTo027(realm).perform()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,10 @@ internal object EventAnnotationsSummaryMapper {
|
|||||||
},
|
},
|
||||||
pollResponseSummary = annotationsSummary.pollResponseSummary?.let {
|
pollResponseSummary = annotationsSummary.pollResponseSummary?.let {
|
||||||
PollResponseAggregatedSummaryEntityMapper.map(it)
|
PollResponseAggregatedSummaryEntityMapper.map(it)
|
||||||
|
},
|
||||||
|
liveLocationShareAggregatedSummary = annotationsSummary.liveLocationShareAggregatedSummary?.let {
|
||||||
|
LiveLocationShareAggregatedSummaryMapper.map(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.internal.database.mapper
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||||
|
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
|
||||||
|
|
||||||
|
internal object LiveLocationShareAggregatedSummaryMapper {
|
||||||
|
|
||||||
|
fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
|
||||||
|
return LiveLocationShareAggregatedSummary(
|
||||||
|
isActive = entity.isActive,
|
||||||
|
endOfLiveTimestampMillis = entity.endOfLiveTimestampMillis,
|
||||||
|
lastLocationDataContent = ContentMapper.map(entity.lastLocationContent).toModel<MessageBeaconLocationDataContent>()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.internal.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import io.realm.FieldAttribute
|
||||||
|
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrating to:
|
||||||
|
* Live location sharing aggregated summary
|
||||||
|
*/
|
||||||
|
internal class MigrateSessionTo027(realm: DynamicRealm) : RealmMigrator(realm, 27) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
val liveLocationSummaryEntity = realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
|
||||||
|
?: realm.schema.create("LiveLocationShareAggregatedSummaryEntity")
|
||||||
|
.addField(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, String::class.java, FieldAttribute.REQUIRED)
|
||||||
|
.addField(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, String::class.java, FieldAttribute.REQUIRED)
|
||||||
|
.addField(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, Boolean::class.java)
|
||||||
|
.setNullable(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
|
||||||
|
.addField(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, Long::class.java)
|
||||||
|
.setNullable(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, true)
|
||||||
|
.addField(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT, String::class.java)
|
||||||
|
?: return
|
||||||
|
|
||||||
|
realm.schema.get("EventAnnotationsSummaryEntity")
|
||||||
|
?.addRealmObjectField(EventAnnotationsSummaryEntityFields.LIVE_LOCATION_SHARE_AGGREGATED_SUMMARY.`$`, liveLocationSummaryEntity)
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.model
|
|||||||
import io.realm.RealmList
|
import io.realm.RealmList
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.annotations.PrimaryKey
|
||||||
|
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal open class EventAnnotationsSummaryEntity(
|
internal open class EventAnnotationsSummaryEntity(
|
||||||
@ -27,7 +28,8 @@ internal open class EventAnnotationsSummaryEntity(
|
|||||||
var reactionsSummary: RealmList<ReactionAggregatedSummaryEntity> = RealmList(),
|
var reactionsSummary: RealmList<ReactionAggregatedSummaryEntity> = RealmList(),
|
||||||
var editSummary: EditAggregatedSummaryEntity? = null,
|
var editSummary: EditAggregatedSummaryEntity? = null,
|
||||||
var referencesSummaryEntity: ReferencesAggregatedSummaryEntity? = null,
|
var referencesSummaryEntity: ReferencesAggregatedSummaryEntity? = null,
|
||||||
var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null
|
var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null,
|
||||||
|
var liveLocationShareAggregatedSummary: LiveLocationShareAggregatedSummaryEntity? = null,
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package org.matrix.android.sdk.internal.database.model
|
package org.matrix.android.sdk.internal.database.model
|
||||||
|
|
||||||
import io.realm.annotations.RealmModule
|
import io.realm.annotations.RealmModule
|
||||||
|
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
|
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
|
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,
|
EditAggregatedSummaryEntity::class,
|
||||||
EditionOfEvent::class,
|
EditionOfEvent::class,
|
||||||
PollResponseAggregatedSummaryEntity::class,
|
PollResponseAggregatedSummaryEntity::class,
|
||||||
|
LiveLocationShareAggregatedSummaryEntity::class,
|
||||||
ReferencesAggregatedSummaryEntity::class,
|
ReferencesAggregatedSummaryEntity::class,
|
||||||
PushRulesEntity::class,
|
PushRulesEntity::class,
|
||||||
PushRuleEntity::class,
|
PushRuleEntity::class,
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.internal.database.model.livelocation
|
||||||
|
|
||||||
|
import io.realm.RealmObject
|
||||||
|
import io.realm.annotations.PrimaryKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregation info concerning a live location share.
|
||||||
|
*/
|
||||||
|
internal open class LiveLocationShareAggregatedSummaryEntity(
|
||||||
|
/**
|
||||||
|
* Event id of the event that started the live.
|
||||||
|
*/
|
||||||
|
@PrimaryKey
|
||||||
|
var eventId: String = "",
|
||||||
|
|
||||||
|
var roomId: String = "",
|
||||||
|
|
||||||
|
var isActive: Boolean? = null,
|
||||||
|
|
||||||
|
var endOfLiveTimestampMillis: Long? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For now we persist this as a JSON for greater flexibility
|
||||||
|
* @see [org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent]
|
||||||
|
*/
|
||||||
|
var lastLocationContent: String? = null,
|
||||||
|
) : RealmObject() {
|
||||||
|
companion object
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.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.LiveLocationShareAggregatedSummaryEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
|
||||||
|
|
||||||
|
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where(
|
||||||
|
realm: Realm,
|
||||||
|
roomId: String,
|
||||||
|
eventId: String,
|
||||||
|
): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
|
||||||
|
return realm.where<LiveLocationShareAggregatedSummaryEntity>()
|
||||||
|
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, roomId)
|
||||||
|
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.create(
|
||||||
|
realm: Realm,
|
||||||
|
roomId: String,
|
||||||
|
eventId: String,
|
||||||
|
): LiveLocationShareAggregatedSummaryEntity {
|
||||||
|
val obj = realm.createObject(LiveLocationShareAggregatedSummaryEntity::class.java, eventId).apply {
|
||||||
|
this.roomId = roomId
|
||||||
|
}
|
||||||
|
val annotationSummary = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId = roomId, eventId = eventId)
|
||||||
|
annotationSummary.liveLocationShareAggregatedSummary = obj
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.getOrCreate(
|
||||||
|
realm: Realm,
|
||||||
|
roomId: String,
|
||||||
|
eventId: String,
|
||||||
|
): LiveLocationShareAggregatedSummaryEntity {
|
||||||
|
return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
|
||||||
|
?: LiveLocationShareAggregatedSummaryEntity.create(realm, roomId, eventId)
|
||||||
|
}
|
@ -33,9 +33,10 @@ 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.ReferencesAggregatedContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.VoteInfo
|
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.VoteSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
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.MessageEndPollContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
|
||||||
@ -91,7 +92,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
// EventType.KEY_VERIFICATION_READY,
|
// EventType.KEY_VERIFICATION_READY,
|
||||||
EventType.KEY_VERIFICATION_KEY,
|
EventType.KEY_VERIFICATION_KEY,
|
||||||
EventType.ENCRYPTED
|
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 {
|
override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean {
|
||||||
return allowedTypes.contains(eventType)
|
return allowedTypes.contains(eventType)
|
||||||
@ -106,12 +107,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
}
|
}
|
||||||
val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
|
val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
|
||||||
when (event.type) {
|
when (event.type) {
|
||||||
EventType.REACTION -> {
|
EventType.REACTION -> {
|
||||||
// we got a reaction!!
|
// we got a reaction!!
|
||||||
Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}")
|
Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}")
|
||||||
handleReaction(realm, event, roomId, isLocalEcho)
|
handleReaction(realm, event, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
EventType.MESSAGE -> {
|
EventType.MESSAGE -> {
|
||||||
if (event.unsignedData?.relations?.annotations != null) {
|
if (event.unsignedData?.relations?.annotations != null) {
|
||||||
Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}")
|
Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}")
|
||||||
handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations)
|
handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations)
|
||||||
@ -137,7 +138,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
EventType.KEY_VERIFICATION_START,
|
EventType.KEY_VERIFICATION_START,
|
||||||
EventType.KEY_VERIFICATION_MAC,
|
EventType.KEY_VERIFICATION_MAC,
|
||||||
EventType.KEY_VERIFICATION_READY,
|
EventType.KEY_VERIFICATION_READY,
|
||||||
EventType.KEY_VERIFICATION_KEY -> {
|
EventType.KEY_VERIFICATION_KEY -> {
|
||||||
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
|
||||||
event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
|
event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
|
||||||
if (it.type == RelationType.REFERENCE && it.eventId != null) {
|
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
|
// Relation type is in clear
|
||||||
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()
|
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()
|
||||||
if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE ||
|
if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE ||
|
||||||
@ -189,8 +190,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
in EventType.BEACON_LOCATION_DATA -> {
|
in EventType.BEACON_LOCATION_DATA -> {
|
||||||
event.content.toModel<MessageLiveLocationContent>(catchError = true)?.let {
|
event.getClearContent().toModel<MessageBeaconLocationDataContent>(catchError = true)?.let {
|
||||||
liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho)
|
liveLocationAggregationProcessor.handleBeaconLocationData(realm, event, it, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +214,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
EventType.REDACTION -> {
|
EventType.REDACTION -> {
|
||||||
val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() }
|
val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() }
|
||||||
?: return
|
?: return
|
||||||
when (eventToPrune.type) {
|
when (eventToPrune.type) {
|
||||||
@ -233,7 +234,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in EventType.POLL_START -> {
|
in EventType.POLL_START -> {
|
||||||
val content: MessagePollContent? = event.content.toModel()
|
val content: MessagePollContent? = event.content.toModel()
|
||||||
if (content?.relatesTo?.type == RelationType.REPLACE) {
|
if (content?.relatesTo?.type == RelationType.REPLACE) {
|
||||||
Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
|
Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
|
||||||
@ -241,22 +242,22 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
handleReplace(realm, event, content, roomId, isLocalEcho)
|
handleReplace(realm, event, content, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in EventType.POLL_RESPONSE -> {
|
in EventType.POLL_RESPONSE -> {
|
||||||
event.content.toModel<MessagePollResponseContent>(catchError = true)?.let {
|
event.content.toModel<MessagePollResponseContent>(catchError = true)?.let {
|
||||||
handleResponse(realm, event, it, roomId, isLocalEcho)
|
handleResponse(realm, event, it, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in EventType.POLL_END -> {
|
in EventType.POLL_END -> {
|
||||||
event.content.toModel<MessageEndPollContent>(catchError = true)?.let {
|
event.content.toModel<MessageEndPollContent>(catchError = true)?.let {
|
||||||
handleEndPoll(realm, event, it, roomId, isLocalEcho)
|
handleEndPoll(realm, event, it, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in EventType.BEACON_LOCATION_DATA -> {
|
in EventType.STATE_ROOM_BEACON_INFO -> {
|
||||||
event.content.toModel<MessageLiveLocationContent>(catchError = true)?.let {
|
event.content.toModel<MessageBeaconInfoContent>(catchError = true)?.let {
|
||||||
liveLocationAggregationProcessor.handleLiveLocation(realm, event, it, roomId, isLocalEcho)
|
liveLocationAggregationProcessor.handleBeaconInfo(realm, event, it, roomId, isLocalEcho)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> Timber.v("UnHandled event ${event.eventId}")
|
else -> Timber.v("UnHandled event ${event.eventId}")
|
||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
Timber.e(t, "## Should not happen ")
|
Timber.e(t, "## Should not happen ")
|
||||||
@ -325,7 +326,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
totalVotes = 0,
|
totalVotes = 0,
|
||||||
winnerVoteCount = 0,
|
winnerVoteCount = 0,
|
||||||
)
|
)
|
||||||
.toContent())
|
.toContent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val txId = event.unsignedData?.transactionId
|
val txId = event.unsignedData?.transactionId
|
||||||
@ -729,11 +731,13 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
|||||||
EventType.KEY_VERIFICATION_READY,
|
EventType.KEY_VERIFICATION_READY,
|
||||||
EventType.KEY_VERIFICATION_KEY,
|
EventType.KEY_VERIFICATION_KEY,
|
||||||
EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING)
|
EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING)
|
||||||
EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(if (event.senderId == userId) {
|
EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(
|
||||||
VerificationState.CANCELED_BY_ME
|
if (event.senderId == userId) {
|
||||||
} else {
|
VerificationState.CANCELED_BY_ME
|
||||||
VerificationState.CANCELED_BY_OTHER
|
} else {
|
||||||
})
|
VerificationState.CANCELED_BY_OTHER
|
||||||
|
}
|
||||||
|
)
|
||||||
EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE)
|
EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE)
|
||||||
else -> VerificationState.REQUEST
|
else -> VerificationState.REQUEST
|
||||||
}
|
}
|
||||||
|
@ -17,69 +17,78 @@
|
|||||||
package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
|
package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
|
||||||
|
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orTrue
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
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.toContent
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
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.MessageBeaconInfoContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
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.model.livelocation.LiveLocationShareAggregatedSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.query.getOrNull
|
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor {
|
internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor {
|
||||||
|
|
||||||
override fun handleLiveLocation(realm: Realm, event: Event, content: MessageLiveLocationContent, roomId: String, isLocalEcho: Boolean) {
|
override fun handleBeaconInfo(realm: Realm, event: Event, content: MessageBeaconInfoContent, roomId: String, isLocalEcho: Boolean) {
|
||||||
val locationSenderId = event.senderId ?: return
|
if (event.senderId.isNullOrEmpty() || isLocalEcho) {
|
||||||
|
|
||||||
// We shouldn't process local echos
|
|
||||||
if (isLocalEcho) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// A beacon info state event has to be sent before sending location
|
val targetEventId = if (content.isLive.orTrue()) {
|
||||||
// TODO handle missing check of m_relatesTo field
|
event.eventId
|
||||||
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 {
|
} else {
|
||||||
beaconInfoContent.lastLocationContent = content
|
// when live is set to false, we use the id of the event that should have been replaced
|
||||||
|
event.unsignedData?.replacesState
|
||||||
}
|
}
|
||||||
|
|
||||||
beaconInfoEntity.root?.content = ContentMapper.map(beaconInfoContent.toContent())
|
if (targetEventId.isNullOrEmpty()) {
|
||||||
|
Timber.w("no target event id found for the beacon content")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
|
||||||
|
realm = realm,
|
||||||
|
roomId = roomId,
|
||||||
|
eventId = targetEventId
|
||||||
|
)
|
||||||
|
|
||||||
|
Timber.d("updating summary of id=$targetEventId with isLive=${content.isLive}")
|
||||||
|
|
||||||
|
aggregatedSummary.endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) }
|
||||||
|
aggregatedSummary.isActive = content.isLive
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isBeaconInfoOutdated(beaconInfoContent: LiveLocationBeaconContent,
|
override fun handleBeaconLocationData(realm: Realm, event: Event, content: MessageBeaconLocationDataContent, roomId: String, isLocalEcho: Boolean) {
|
||||||
liveLocationContent: MessageLiveLocationContent): Boolean {
|
if (event.senderId.isNullOrEmpty() || isLocalEcho) {
|
||||||
val beaconInfoStartTime = beaconInfoContent.getBestTimestampAsMilliseconds() ?: 0
|
return
|
||||||
val liveLocationEventTime = liveLocationContent.getBestTimestampAsMilliseconds() ?: 0
|
}
|
||||||
val timeout = beaconInfoContent.timeout ?: 0
|
|
||||||
return liveLocationEventTime - beaconInfoStartTime > timeout
|
val targetEventId = content.relatesTo?.eventId
|
||||||
|
|
||||||
|
if (targetEventId.isNullOrEmpty()) {
|
||||||
|
Timber.w("no target event id found for the live location content")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
|
||||||
|
realm = realm,
|
||||||
|
roomId = roomId,
|
||||||
|
eventId = targetEventId
|
||||||
|
)
|
||||||
|
val updatedLocationTimestamp = content.getBestTimestampMillis() ?: 0
|
||||||
|
val currentLocationTimestamp = ContentMapper
|
||||||
|
.map(aggregatedSummary.lastLocationContent)
|
||||||
|
.toModel<MessageBeaconLocationDataContent>()
|
||||||
|
?.getBestTimestampMillis()
|
||||||
|
?: 0
|
||||||
|
|
||||||
|
if (updatedLocationTimestamp.isMoreRecentThan(currentLocationTimestamp)) {
|
||||||
|
Timber.d("updating last location of the summary of id=$targetEventId")
|
||||||
|
aggregatedSummary.lastLocationContent = ContentMapper.map(content.toContent())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Long.isMoreRecentThan(timestamp: Long) = this > timestamp
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,23 @@ package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
|
|||||||
|
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||||
|
|
||||||
internal interface LiveLocationAggregationProcessor {
|
internal interface LiveLocationAggregationProcessor {
|
||||||
fun handleLiveLocation(realm: Realm,
|
fun handleBeaconInfo(
|
||||||
event: Event,
|
realm: Realm,
|
||||||
content: MessageLiveLocationContent,
|
event: Event,
|
||||||
roomId: String,
|
content: MessageBeaconInfoContent,
|
||||||
isLocalEcho: Boolean)
|
roomId: String,
|
||||||
|
isLocalEcho: Boolean,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun handleBeaconLocationData(
|
||||||
|
realm: Realm,
|
||||||
|
event: Event,
|
||||||
|
content: MessageBeaconLocationDataContent,
|
||||||
|
roomId: String,
|
||||||
|
isLocalEcho: Boolean,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -37,13 +37,13 @@ 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.LocationAssetType
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.LocationInfo
|
import org.matrix.android.sdk.api.session.room.model.message.LocationInfo
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
|
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLiveLocationContent
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
|
||||||
@ -71,7 +71,6 @@ import org.matrix.android.sdk.internal.session.content.ThumbnailExtractor
|
|||||||
import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory
|
import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory
|
||||||
import org.matrix.android.sdk.internal.session.room.send.pills.TextPillsUtils
|
import org.matrix.android.sdk.internal.session.room.send.pills.TextPillsUtils
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,7 +123,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
newBodyAutoMarkdown: Boolean,
|
newBodyAutoMarkdown: Boolean,
|
||||||
msgType: String,
|
msgType: String,
|
||||||
compatibilityText: String): Event {
|
compatibilityText: String): Event {
|
||||||
return createMessageEvent(roomId,
|
return createMessageEvent(
|
||||||
|
roomId,
|
||||||
MessageTextContent(
|
MessageTextContent(
|
||||||
msgType = msgType,
|
msgType = msgType,
|
||||||
body = compatibilityText,
|
body = compatibilityText,
|
||||||
@ -132,7 +132,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
newContent = createTextContent(newBodyText, newBodyAutoMarkdown)
|
newContent = createTextContent(newBodyText, newBodyAutoMarkdown)
|
||||||
.toMessageTextContent(msgType)
|
.toMessageTextContent(msgType)
|
||||||
.toContent()
|
.toContent()
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createPollContent(question: String,
|
private fun createPollContent(question: String,
|
||||||
@ -188,7 +189,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.POLL_RESPONSE.first(),
|
type = EventType.POLL_RESPONSE.first(),
|
||||||
content = content.toContent(),
|
content = content.toContent(),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId))
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPollEvent(roomId: String,
|
fun createPollEvent(roomId: String,
|
||||||
@ -204,7 +206,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.POLL_START.first(),
|
type = EventType.POLL_START.first(),
|
||||||
content = content.toContent(),
|
content = content.toContent(),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId))
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createEndPollEvent(roomId: String,
|
fun createEndPollEvent(roomId: String,
|
||||||
@ -223,7 +226,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.POLL_END.first(),
|
type = EventType.POLL_END.first(),
|
||||||
content = content.toContent(),
|
content = content.toContent(),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId))
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createLocationEvent(roomId: String,
|
fun createLocationEvent(roomId: String,
|
||||||
@ -238,7 +242,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
body = geoUri,
|
body = geoUri,
|
||||||
unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri),
|
unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri),
|
||||||
unstableLocationAsset = LocationAsset(type = assetType),
|
unstableLocationAsset = LocationAsset(type = assetType),
|
||||||
unstableTs = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()),
|
unstableTimestampMillis = System.currentTimeMillis(),
|
||||||
unstableText = geoUri
|
unstableText = geoUri
|
||||||
)
|
)
|
||||||
return createMessageEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
@ -250,14 +254,14 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
longitude: Double,
|
longitude: Double,
|
||||||
uncertainty: Double?): Event {
|
uncertainty: Double?): Event {
|
||||||
val geoUri = buildGeoUri(latitude, longitude, uncertainty)
|
val geoUri = buildGeoUri(latitude, longitude, uncertainty)
|
||||||
val content = MessageLiveLocationContent(
|
val content = MessageBeaconLocationDataContent(
|
||||||
body = geoUri,
|
body = geoUri,
|
||||||
relatesTo = RelationDefaultContent(
|
relatesTo = RelationDefaultContent(
|
||||||
type = RelationType.REFERENCE,
|
type = RelationType.REFERENCE,
|
||||||
eventId = beaconInfoEventId
|
eventId = beaconInfoEventId
|
||||||
),
|
),
|
||||||
unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri),
|
unstableLocationInfo = LocationInfo(geoUri = geoUri, description = geoUri),
|
||||||
unstableTimestampAsMilliseconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()),
|
unstableTimestampMillis = System.currentTimeMillis(),
|
||||||
)
|
)
|
||||||
val localId = LocalEcho.createLocalEchoId()
|
val localId = LocalEcho.createLocalEchoId()
|
||||||
return Event(
|
return Event(
|
||||||
@ -267,7 +271,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.BEACON_LOCATION_DATA.first(),
|
type = EventType.BEACON_LOCATION_DATA.first(),
|
||||||
content = content.toContent(),
|
content = content.toContent(),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId))
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createReplaceTextOfReply(roomId: String,
|
fun createReplaceTextOfReply(roomId: String,
|
||||||
@ -297,7 +302,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
//
|
//
|
||||||
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText)
|
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText)
|
||||||
|
|
||||||
return createMessageEvent(roomId,
|
return createMessageEvent(
|
||||||
|
roomId,
|
||||||
MessageTextContent(
|
MessageTextContent(
|
||||||
msgType = msgType,
|
msgType = msgType,
|
||||||
body = compatibilityText,
|
body = compatibilityText,
|
||||||
@ -309,7 +315,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
formattedBody = replyFormatted
|
formattedBody = replyFormatted
|
||||||
)
|
)
|
||||||
.toContent()
|
.toContent()
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createMediaEvent(roomId: String,
|
fun createMediaEvent(roomId: String,
|
||||||
@ -341,7 +348,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.REACTION,
|
type = EventType.REACTION,
|
||||||
content = content.toContent(),
|
content = content.toContent(),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId))
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createImageEvent(roomId: String, attachment: ContentAttachmentData, rootThreadEventId: String?): Event {
|
private fun createImageEvent(roomId: String, attachment: ContentAttachmentData, rootThreadEventId: String?): Event {
|
||||||
@ -532,8 +540,10 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
content.toThreadTextContent(
|
content.toThreadTextContent(
|
||||||
rootThreadEventId = rootThreadEventId,
|
rootThreadEventId = rootThreadEventId,
|
||||||
latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId),
|
latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId),
|
||||||
msgType = msgType)
|
msgType = msgType
|
||||||
.toContent())
|
)
|
||||||
|
.toContent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dummyOriginServerTs(): Long {
|
private fun dummyOriginServerTs(): Long {
|
||||||
@ -582,7 +592,9 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
relatesTo = generateReplyRelationContent(
|
relatesTo = generateReplyRelationContent(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
rootThreadEventId = rootThreadEventId,
|
rootThreadEventId = rootThreadEventId,
|
||||||
showInThread = showInThread))
|
showInThread = showInThread
|
||||||
|
)
|
||||||
|
)
|
||||||
return createMessageEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,7 +617,8 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
eventId = it,
|
eventId = it,
|
||||||
isFallingBack = showInThread,
|
isFallingBack = showInThread,
|
||||||
// False when is a rich reply from within a thread, and true when is a reply that should be visible from threads
|
// False when is a rich reply from within a thread, and true when is a reply that should be visible from threads
|
||||||
inReplyTo = ReplyToContent(eventId = eventId))
|
inReplyTo = ReplyToContent(eventId = eventId)
|
||||||
|
)
|
||||||
} ?: RelationDefaultContent(null, null, ReplyToContent(eventId = eventId))
|
} ?: RelationDefaultContent(null, null, ReplyToContent(eventId = eventId))
|
||||||
|
|
||||||
private fun buildFormattedReply(permalink: String, userLink: String, userId: String, bodyFormatted: String, newBodyFormatted: String): String {
|
private fun buildFormattedReply(permalink: String, userLink: String, userId: String, bodyFormatted: String, newBodyFormatted: String): String {
|
||||||
@ -740,13 +753,15 @@ internal class LocalEchoEventFactory @Inject constructor(
|
|||||||
.toThreadTextContent(
|
.toThreadTextContent(
|
||||||
rootThreadEventId = rootThreadEventId,
|
rootThreadEventId = rootThreadEventId,
|
||||||
latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId),
|
latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId),
|
||||||
msgType = MessageType.MSGTYPE_TEXT)
|
msgType = MessageType.MSGTYPE_TEXT
|
||||||
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
createFormattedTextEvent(
|
createFormattedTextEvent(
|
||||||
roomId,
|
roomId,
|
||||||
markdownParser.parse(quoteText, force = true, advanced = autoMarkdown),
|
markdownParser.parse(quoteText, force = true, advanced = autoMarkdown),
|
||||||
MessageType.MSGTYPE_TEXT)
|
MessageType.MSGTYPE_TEXT
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
|||||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||||
import org.matrix.android.sdk.api.session.room.state.StateService
|
import org.matrix.android.sdk.api.session.room.state.StateService
|
||||||
import org.matrix.android.sdk.api.util.JsonDict
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
import org.matrix.android.sdk.api.util.MimeTypes
|
import org.matrix.android.sdk.api.util.MimeTypes
|
||||||
@ -192,7 +192,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
|
|||||||
|
|
||||||
override suspend fun stopLiveLocation(userId: String) {
|
override suspend fun stopLiveLocation(userId: String) {
|
||||||
getLiveLocationBeaconInfo(userId, true)?.let { beaconInfoStateEvent ->
|
getLiveLocationBeaconInfo(userId, true)?.let { beaconInfoStateEvent ->
|
||||||
beaconInfoStateEvent.getClearContent()?.toModel<LiveLocationBeaconContent>()?.let { content ->
|
beaconInfoStateEvent.getClearContent()?.toModel<MessageBeaconInfoContent>()?.let { content ->
|
||||||
val updatedContent = content.copy(isLive = false).toContent()
|
val updatedContent = content.copy(isLive = false).toContent()
|
||||||
|
|
||||||
beaconInfoStateEvent.stateKey?.let {
|
beaconInfoStateEvent.stateKey?.let {
|
||||||
@ -217,7 +217,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
|
|||||||
}
|
}
|
||||||
.firstOrNull { beaconInfoEvent ->
|
.firstOrNull { beaconInfoEvent ->
|
||||||
!filterOnlyLive ||
|
!filterOnlyLive ||
|
||||||
beaconInfoEvent.getClearContent()?.toModel<LiveLocationBeaconContent>()?.isLive.orFalse()
|
beaconInfoEvent.getClearContent()?.toModel<MessageBeaconInfoContent>()?.isLive.orFalse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem
|
|||||||
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem
|
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem_
|
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem_
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LiveLocationMessageItemFactory @Inject constructor(
|
class LiveLocationMessageItemFactory @Inject constructor(
|
||||||
@ -34,19 +34,20 @@ class LiveLocationMessageItemFactory @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun create(
|
fun create(
|
||||||
liveLocationContent: LiveLocationBeaconContent,
|
beaconInfoContent: MessageBeaconInfoContent,
|
||||||
highlight: Boolean,
|
highlight: Boolean,
|
||||||
attributes: AbsMessageItem.Attributes,
|
attributes: AbsMessageItem.Attributes,
|
||||||
): VectorEpoxyModel<*>? {
|
): VectorEpoxyModel<*>? {
|
||||||
// TODO handle location received and stopped states
|
// TODO handle location received and stopped states
|
||||||
return when {
|
return when {
|
||||||
isLiveRunning(liveLocationContent) -> buildStartLiveItem(highlight, attributes)
|
isLiveRunning(beaconInfoContent) -> buildStartLiveItem(highlight, attributes)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isLiveRunning(liveLocationContent: LiveLocationBeaconContent): Boolean {
|
private fun isLiveRunning(beaconInfoContent: MessageBeaconInfoContent): Boolean {
|
||||||
return liveLocationContent.isLive.orFalse() && liveLocationContent.hasTimedOut.not()
|
// TODO when we will use aggregatedSummary, check if the live has timed out as well
|
||||||
|
return beaconInfoContent.isLive.orFalse()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildStartLiveItem(
|
private fun buildStartLiveItem(
|
||||||
|
@ -98,8 +98,8 @@ import org.matrix.android.sdk.api.session.events.model.RelationType
|
|||||||
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
|
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
|
||||||
import org.matrix.android.sdk.api.session.events.model.isThread
|
import org.matrix.android.sdk.api.session.events.model.isThread
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
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.MessageAudioContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageEmoteContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageEmoteContent
|
||||||
@ -207,15 +207,15 @@ class MessageItemFactory @Inject constructor(
|
|||||||
is MessageAudioContent -> buildAudioContent(params, messageContent, informationData, highlight, attributes)
|
is MessageAudioContent -> buildAudioContent(params, messageContent, informationData, highlight, attributes)
|
||||||
is MessageVerificationRequestContent -> buildVerificationRequestMessageItem(messageContent, informationData, highlight, callback, attributes)
|
is MessageVerificationRequestContent -> buildVerificationRequestMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes)
|
is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
is MessageLocationContent -> {
|
is MessageLocationContent -> {
|
||||||
if (vectorPreferences.labsRenderLocationsInTimeline()) {
|
if (vectorPreferences.labsRenderLocationsInTimeline()) {
|
||||||
buildLocationItem(messageContent, informationData, highlight, attributes)
|
buildLocationItem(messageContent, informationData, highlight, attributes)
|
||||||
} else {
|
} else {
|
||||||
buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes)
|
buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is LiveLocationBeaconContent -> liveLocationMessageItemFactory.create(messageContent, highlight, attributes)
|
is MessageBeaconInfoContent -> liveLocationMessageItemFactory.create(messageContent, highlight, attributes)
|
||||||
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
|
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
|
||||||
}
|
}
|
||||||
return messageItem?.apply {
|
return messageItem?.apply {
|
||||||
layout(informationData.messageLayout.layoutRes)
|
layout(informationData.messageLayout.layoutRes)
|
||||||
|
@ -59,12 +59,12 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess
|
|||||||
MessageType.MSGTYPE_VIDEO,
|
MessageType.MSGTYPE_VIDEO,
|
||||||
MessageType.MSGTYPE_STICKER_LOCAL,
|
MessageType.MSGTYPE_STICKER_LOCAL,
|
||||||
MessageType.MSGTYPE_EMOTE,
|
MessageType.MSGTYPE_EMOTE,
|
||||||
MessageType.MSGTYPE_LIVE_LOCATION_STATE,
|
MessageType.MSGTYPE_BEACON_INFO,
|
||||||
)
|
)
|
||||||
private val MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE = setOf(
|
private val MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE = setOf(
|
||||||
MessageType.MSGTYPE_IMAGE,
|
MessageType.MSGTYPE_IMAGE,
|
||||||
MessageType.MSGTYPE_VIDEO,
|
MessageType.MSGTYPE_VIDEO,
|
||||||
MessageType.MSGTYPE_LIVE_LOCATION_STATE,
|
MessageType.MSGTYPE_BEACON_INFO,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,8 +151,8 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess
|
|||||||
|
|
||||||
private fun MessageContent?.shouldAddMessageOverlay(): Boolean {
|
private fun MessageContent?.shouldAddMessageOverlay(): Boolean {
|
||||||
return when {
|
return when {
|
||||||
this == null || msgType == MessageType.MSGTYPE_LIVE_LOCATION_STATE -> false
|
this == null || msgType == MessageType.MSGTYPE_BEACON_INFO -> false
|
||||||
msgType == MessageType.MSGTYPE_LOCATION -> vectorPreferences.labsRenderLocationsInTimeline()
|
msgType == MessageType.MSGTYPE_LOCATION -> vectorPreferences.labsRenderLocationsInTimeline()
|
||||||
else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE
|
else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ 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.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
import org.matrix.android.sdk.api.session.getRoom
|
import org.matrix.android.sdk.api.session.getRoom
|
||||||
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationBeaconContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.Timer
|
import java.util.Timer
|
||||||
import java.util.TimerTask
|
import java.util.TimerTask
|
||||||
@ -96,10 +96,10 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun sendLiveBeaconInfo(session: Session, roomArgs: RoomArgs) {
|
private suspend fun sendLiveBeaconInfo(session: Session, roomArgs: RoomArgs) {
|
||||||
val beaconContent = LiveLocationBeaconContent(
|
val beaconContent = MessageBeaconInfoContent(
|
||||||
timeout = roomArgs.durationMillis,
|
timeout = roomArgs.durationMillis,
|
||||||
isLive = true,
|
isLive = true,
|
||||||
unstableTimestampAsMilliseconds = clock.epochMillis()
|
unstableTimestampMillis = clock.epochMillis()
|
||||||
).toContent()
|
).toContent()
|
||||||
|
|
||||||
val stateKey = session.myUserId
|
val stateKey = session.myUserId
|
||||||
|
Loading…
Reference in New Issue
Block a user