Refactor a bit EnrichedEvent and Content. Metadata will only be used for unexpected data.

This commit is contained in:
ganfra 2018-12-18 12:13:46 +01:00
parent de4281c954
commit 39ad44e9aa
16 changed files with 73 additions and 129 deletions

View File

@ -1,7 +1,7 @@
package im.vector.riotredesign.features.home.room.detail.timeline
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
import im.vector.matrix.android.api.session.events.model.roomMember
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.MessageContent
import org.threeten.bp.LocalDateTime
@ -10,12 +10,12 @@ class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatte
private val messagesDisplayedWithInformation = HashSet<String?>()
fun create(event: EnrichedEvent, nextEvent: EnrichedEvent?, addDaySeparator: Boolean, date: LocalDateTime): MessageItem? {
val messageContent = event.root.content<MessageContent>()
val roomMember = event.roomMember()
val messageContent: MessageContent? = event.root.content.toModel()
val roomMember = event.roomMember
if (messageContent == null || roomMember == null) {
return null
}
val nextRoomMember = nextEvent?.roomMember()
val nextRoomMember = nextEvent?.roomMember
if (addDaySeparator || nextRoomMember != roomMember) {
messagesDisplayedWithInformation.add(event.root.eventId)
}

View File

@ -5,7 +5,6 @@ import com.airbnb.epoxy.EpoxyAsyncUtil
import com.airbnb.epoxy.EpoxyController
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.localId
import im.vector.riotredesign.core.extensions.localDateTime
import im.vector.riotredesign.features.home.LoadingItemModel_
@ -67,7 +66,7 @@ class TimelineEventController(private val roomId: String,
}
item
?.onBind { timeline?.loadAround(index) }
?.id(event.localId())
?.id(event.localId)
?.addTo(this)
if (addDaySeparator) {

View File

@ -2,7 +2,11 @@ package im.vector.matrix.android.api.session.events.model
import im.vector.matrix.android.api.session.room.model.RoomMember
data class EnrichedEvent(val root: Event) {
data class EnrichedEvent(
val root: Event,
val localId: String,
val roomMember: RoomMember?
) {
val metadata = HashMap<String, Any>()
@ -18,20 +22,4 @@ data class EnrichedEvent(val root: Event) {
inline fun <reified T> getMetadata(key: String): T? {
return metadata[key] as T?
}
companion object {
const val ROOM_MEMBER = "ROOM_MEMBER"
const val IS_LAST_EVENT = "IS_LAST_EVENT"
const val READ_RECEIPTS = "READ_RECEIPTS"
const val LOCAL_ID = "LOCAL_ID"
}
}
fun EnrichedEvent.roomMember(): RoomMember? {
return getMetadata<RoomMember>(EnrichedEvent.ROOM_MEMBER)
}
fun EnrichedEvent.localId(): String? {
return getMetadata<String>(EnrichedEvent.LOCAL_ID)
}

View File

@ -8,6 +8,14 @@ import java.lang.reflect.ParameterizedType
typealias Content = Map<String, @JvmSuppressWildcards Any>
inline fun <reified T> Content?.toModel(): T? {
return this?.let {
val moshi = MoshiProvider.providesMoshi()
val moshiAdapter = moshi.adapter(T::class.java)
return moshiAdapter.fromJsonValue(it)
}
}
@JsonClass(generateAdapter = true)
data class Event(
@Json(name = "type") val type: String,
@ -27,28 +35,6 @@ data class Event(
return EventType.isStateEvent(type)
}
inline fun <reified T> content(): T? {
return toModel(content)
}
inline fun <reified T> prevContent(): T? {
return toModel(prevContent)
}
inline fun <reified T> toModel(data: Content?): T? {
val moshi = MoshiProvider.providesMoshi()
val moshiAdapter = moshi.adapter(T::class.java)
return moshiAdapter.fromJsonValue(data)
}
internal inline fun <reified T> pickContent(stateIndex: Int): T? {
return if (stateIndex < 0) {
prevContent<T>()
} else {
content<T>()
}
}
companion object {
internal val CONTENT_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)
}

View File

@ -67,4 +67,4 @@ object EventType {
return STATE_EVENTS.contains(type)
}
}
}

View File

@ -10,11 +10,15 @@ internal object ContentMapper {
private val adapter = moshi.adapter<Content>(Event.CONTENT_TYPE)
fun map(content: String?): Content? {
return adapter.fromJson(content ?: "")
return content?.let {
adapter.fromJson(it)
}
}
fun map(content: Content?): String {
return adapter.toJson(content)
fun map(content: Content?): String? {
return content?.let {
adapter.toJson(it)
}
}
}

View File

@ -9,7 +9,7 @@ import java.util.*
internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(),
var eventId: String = "",
var type: String = "",
var content: String = "",
var content: String? = null,
var prevContent: String? = null,
var stateKey: String? = null,
var originServerTs: Long? = null,

View File

@ -1,34 +0,0 @@
package im.vector.matrix.android.internal.session.events.interceptor
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.events.interceptor.EnrichedEventInterceptor
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.room.members.RoomMemberExtractor
internal class MessageEventInterceptor(private val monarchy: Monarchy,
private val roomId: String) : EnrichedEventInterceptor {
override fun canEnrich(event: EnrichedEvent): Boolean {
return event.root.type == EventType.MESSAGE
}
override fun enrich(event: EnrichedEvent) {
monarchy.doWithRealm { realm ->
if (event.root.eventId == null) {
return@doWithRealm
}
val rootEntity = EventEntity.where(realm, eventId = event.root.eventId).findFirst()
?: return@doWithRealm
event.enrichWith(EnrichedEvent.LOCAL_ID, rootEntity.localId)
val roomMember = RoomMemberExtractor(realm, roomId).extractFrom(rootEntity)
event.enrichWith(EnrichedEvent.ROOM_MEMBER, roomMember)
}
}
}

View File

@ -1,11 +1,12 @@
package im.vector.matrix.android.internal.session.room
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.model.MyMembership
import im.vector.matrix.android.api.session.room.model.RoomAvatarContent
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.query.last
@ -24,7 +25,7 @@ internal class RoomAvatarResolver(private val monarchy: Monarchy,
var res: String? = null
monarchy.doWithRealm { realm ->
val roomName = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_AVATAR).last()?.asDomain()
res = roomName?.content<RoomAvatarContent>()?.avatarUrl
res = roomName?.content.toModel<RoomAvatarContent>()?.avatarUrl
if (!res.isNullOrEmpty()) {
return@doWithRealm
}

View File

@ -7,10 +7,11 @@ import im.vector.matrix.android.api.session.room.send.EventFactory
import im.vector.matrix.android.internal.session.DefaultSession
import im.vector.matrix.android.internal.session.room.members.DefaultLoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.members.RoomMemberExtractor
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineHolder
import im.vector.matrix.android.internal.session.room.timeline.DefaultGetContextOfEventTask
import im.vector.matrix.android.internal.session.room.timeline.DefaultPaginationTask
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineHolder
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
import im.vector.matrix.android.internal.session.room.timeline.TimelineBoundaryCallback
@ -54,7 +55,8 @@ class RoomModule {
factory { (roomId: String) ->
val helper = PagingRequestHelper(Executors.newSingleThreadExecutor())
val timelineBoundaryCallback = TimelineBoundaryCallback(roomId, get(), get(), get(), helper)
DefaultTimelineHolder(roomId, get(), get() , timelineBoundaryCallback, get()) as TimelineHolder
val roomMemberExtractor = RoomMemberExtractor(get(), roomId)
DefaultTimelineHolder(roomId, get(), get(), timelineBoundaryCallback, get(), roomMemberExtractor) as TimelineHolder
}
factory { (roomId: String) ->

View File

@ -2,10 +2,11 @@ package im.vector.matrix.android.internal.session.room
import android.content.Context
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.EventEntity
@ -43,7 +44,7 @@ internal class RoomSummaryUpdater(monarchy: Monarchy,
return
}
val roomSummary = RoomSummaryEntity.where(realm, room.roomId).findFirst()
?: realm.createObject(room.roomId)
?: realm.createObject(room.roomId)
val lastMessageEvent = EventEntity.where(realm, room.roomId, EventType.MESSAGE).last()
val lastTopicEvent = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_TOPIC).last()?.asDomain()
@ -52,7 +53,7 @@ internal class RoomSummaryUpdater(monarchy: Monarchy,
roomSummary.displayName = roomDisplayNameResolver.resolve(context, room).toString()
roomSummary.avatarUrl = roomAvatarResolver.resolve(room)
roomSummary.topic = lastTopicEvent?.content<RoomTopicContent>()?.topic
roomSummary.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
roomSummary.lastMessage = lastMessageEvent
roomSummary.otherMemberIds.clear()
roomSummary.otherMemberIds.addAll(otherRoomMembers.keys)

View File

@ -19,13 +19,14 @@ package im.vector.matrix.android.internal.session.room.members
import android.content.Context
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.R
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.model.MyMembership
import im.vector.matrix.android.api.session.room.model.RoomAliasesContent
import im.vector.matrix.android.api.session.room.model.RoomCanonicalAliasContent
import im.vector.matrix.android.api.session.room.model.RoomNameContent
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
@ -57,19 +58,19 @@ internal class RoomDisplayNameResolver(private val monarchy: Monarchy,
var name: CharSequence? = null
monarchy.doWithRealm { realm ->
val roomName = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_NAME).last()?.asDomain()
name = roomName?.content<RoomNameContent>()?.name
name = roomName?.content.toModel<RoomNameContent>()?.name
if (!name.isNullOrEmpty()) {
return@doWithRealm
}
val canonicalAlias = EventEntity.where(realm, room.roomId, EventType.STATE_CANONICAL_ALIAS).last()?.asDomain()
name = canonicalAlias?.content<RoomCanonicalAliasContent>()?.canonicalAlias
name = canonicalAlias?.content.toModel<RoomCanonicalAliasContent>()?.canonicalAlias
if (!name.isNullOrEmpty()) {
return@doWithRealm
}
val aliases = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_ALIASES).last()?.asDomain()
name = aliases?.content<RoomAliasesContent>()?.aliases?.firstOrNull()
name = aliases?.content.toModel<RoomAliasesContent>()?.aliases?.firstOrNull()
if (!name.isNullOrEmpty()) {
return@doWithRealm
}

View File

@ -1,17 +1,18 @@
package im.vector.matrix.android.internal.session.room.members
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.mapper.ContentMapper
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.query.last
import im.vector.matrix.android.internal.database.query.next
import im.vector.matrix.android.internal.database.query.where
import io.realm.Realm
import io.realm.RealmQuery
internal class RoomMemberExtractor(private val realm: Realm,
internal class RoomMemberExtractor(private val monarchy: Monarchy,
private val roomId: String) {
fun extractFrom(event: EventEntity): RoomMember? {
@ -20,24 +21,28 @@ internal class RoomMemberExtractor(private val realm: Realm,
val unlinked = event.isUnlinked
// When stateIndex is negative, we try to get the next stateEvent prevContent()
// If prevContent is null we fallback to the Int.MIN state events content()
return if (event.stateIndex <= 0) {
baseQuery(realm, roomId, sender, unlinked).next(from = event.stateIndex)?.asDomain()?.prevContent()
?: baseQuery(realm, roomId, sender, unlinked).last(since = event.stateIndex)?.asDomain()?.content()
val content = if (event.stateIndex <= 0) {
baseQuery(monarchy, roomId, sender, unlinked).next(from = event.stateIndex)?.prevContent
?: baseQuery(monarchy, roomId, sender, unlinked).last(since = event.stateIndex)?.content
} else {
baseQuery(realm, roomId, sender, unlinked).last(since = event.stateIndex)?.asDomain()?.content()
baseQuery(monarchy, roomId, sender, unlinked).last(since = event.stateIndex)?.content
}
return ContentMapper.map(content).toModel()
}
private fun baseQuery(realm: Realm,
private fun baseQuery(monarchy: Monarchy,
roomId: String,
sender: String,
isUnlinked: Boolean): RealmQuery<EventEntity> {
lateinit var query: RealmQuery<EventEntity>
val filterMode = if (isUnlinked) EventEntity.LinkFilterMode.UNLINKED_ONLY else EventEntity.LinkFilterMode.LINKED_ONLY
return EventEntity
.where(realm, roomId = roomId, type = EventType.STATE_ROOM_MEMBER, linkFilterMode = filterMode)
.equalTo(EventEntityFields.STATE_KEY, sender)
monarchy.doWithRealm { realm ->
query = EventEntity
.where(realm, roomId = roomId, type = EventType.STATE_ROOM_MEMBER, linkFilterMode = filterMode)
.equalTo(EventEntityFields.STATE_KEY, sender)
}
return query
}

View File

@ -1,6 +1,7 @@
package im.vector.matrix.android.internal.session.room.members
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.internal.database.mapper.asDomain
@ -25,7 +26,7 @@ internal class RoomMembers(private val realm: Realm,
.findAll()
.map { it.asDomain() }
.associateBy { it.stateKey!! }
.mapValues { it.value.content<RoomMember>()!! }
.mapValues { it.value.content.toModel<RoomMember>()!! }
}

View File

@ -7,14 +7,14 @@ import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.events.interceptor.EnrichedEventInterceptor
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
import im.vector.matrix.android.api.session.room.TimelineHolder
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.ChunkEntityFields
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.events.interceptor.MessageEventInterceptor
import im.vector.matrix.android.internal.session.room.members.RoomMemberExtractor
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.tryTransactionSync
import io.realm.Realm
import io.realm.RealmQuery
@ -25,15 +25,12 @@ internal class DefaultTimelineHolder(private val roomId: String,
private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor,
private val boundaryCallback: TimelineBoundaryCallback,
private val contextOfEventTask: GetContextOfEventTask
private val contextOfEventTask: GetContextOfEventTask,
private val roomMemberExtractor: RoomMemberExtractor
) : TimelineHolder {
private val eventInterceptors = ArrayList<EnrichedEventInterceptor>()
init {
eventInterceptors.add(MessageEventInterceptor(monarchy, roomId))
}
override fun timeline(eventId: String?): LiveData<PagedList<EnrichedEvent>> {
clearUnlinkedEvents()
if (eventId != null) {
@ -43,17 +40,9 @@ internal class DefaultTimelineHolder(private val roomId: String,
buildDataSourceFactoryQuery(it, eventId)
}
val domainSourceFactory = realmDataSourceFactory
.map { it.asDomain() }
.map { event ->
val enrichedEvent = EnrichedEvent(event)
eventInterceptors
.filter {
it.canEnrich(enrichedEvent)
}.forEach {
it.enrich(enrichedEvent)
}
enrichedEvent
.map { eventEntity ->
val roomMember = roomMemberExtractor.extractFrom(eventEntity)
EnrichedEvent(eventEntity.asDomain(), eventEntity.localId, roomMember)
}
val pagedListConfig = PagedList.Config.Builder()

View File

@ -3,6 +3,7 @@ package im.vector.matrix.android.internal.session.sync
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.MyMembership
import im.vector.matrix.android.internal.database.helper.addAll
import im.vector.matrix.android.internal.database.helper.addOrUpdate
@ -166,7 +167,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
ephemeral: RoomSyncEphemeral) {
ephemeral.events
.filter { it.type == EventType.RECEIPT }
.map { it.content<ReadReceiptContent>() }
.map { it.content.toModel<ReadReceiptContent>() }
.flatMap { readReceiptHandler.handle(realm, roomId, it) }
}
}