mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge pull request #637 from vector-im/feature/fix_room_summary
Feature/fix some room related stuff
This commit is contained in:
commit
b17b54d218
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.events.model
|
||||
|
||||
import java.util.*
|
||||
|
||||
object LocalEcho {
|
||||
|
||||
private const val PREFIX = "local."
|
||||
|
||||
fun isLocalEchoId(eventId: String) = eventId.startsWith(PREFIX)
|
||||
|
||||
fun createLocalEchoId() = "${PREFIX}${UUID.randomUUID()}"
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
||||
|
||||
@ -26,7 +27,9 @@ internal fun isEventRead(monarchy: Monarchy,
|
||||
if (userId.isNullOrBlank() || roomId.isNullOrBlank() || eventId.isNullOrBlank()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (LocalEcho.isLocalEchoId(eventId)) {
|
||||
return true
|
||||
}
|
||||
var isEventRead = false
|
||||
|
||||
monarchy.doWithRealm { realm ->
|
||||
|
@ -61,25 +61,28 @@ internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent(realm:
|
||||
internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm,
|
||||
roomId: String,
|
||||
includesSending: Boolean,
|
||||
includedTypes: List<String> = emptyList(),
|
||||
excludedTypes: List<String> = emptyList()): TimelineEventEntity? {
|
||||
filterTypes: List<String> = emptyList()): TimelineEventEntity? {
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null
|
||||
val eventList = if (includesSending && roomEntity.sendingTimelineEvents.isNotEmpty()) {
|
||||
roomEntity.sendingTimelineEvents
|
||||
val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterTypes(filterTypes)
|
||||
val liveEvents = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.timelineEvents?.where()?.filterTypes(filterTypes)
|
||||
val query = if (includesSending && sendingTimelineEvents.findAll().isNotEmpty()) {
|
||||
sendingTimelineEvents
|
||||
} else {
|
||||
ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.timelineEvents
|
||||
}
|
||||
val query = eventList?.where()
|
||||
if (includedTypes.isNotEmpty()) {
|
||||
query?.`in`(TimelineEventEntityFields.ROOT.TYPE, includedTypes.toTypedArray())
|
||||
} else if (excludedTypes.isNotEmpty()) {
|
||||
query?.not()?.`in`(TimelineEventEntityFields.ROOT.TYPE, excludedTypes.toTypedArray())
|
||||
liveEvents
|
||||
}
|
||||
return query
|
||||
?.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING)
|
||||
?.findFirst()
|
||||
}
|
||||
|
||||
internal fun RealmQuery<TimelineEventEntity>.filterTypes(filterTypes: List<String>): RealmQuery<TimelineEventEntity> {
|
||||
return if (filterTypes.isEmpty()) {
|
||||
this
|
||||
} else {
|
||||
this.`in`(TimelineEventEntityFields.ROOT.TYPE, filterTypes.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RealmQuery<TimelineEventEntity>.next(from: Int? = null, strict: Boolean = true): TimelineEventEntity? {
|
||||
if (from != null) {
|
||||
if (strict) {
|
||||
|
@ -28,7 +28,6 @@ import im.vector.matrix.android.internal.database.mapper.EventMapper
|
||||
import im.vector.matrix.android.internal.database.model.*
|
||||
import im.vector.matrix.android.internal.database.query.create
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import io.realm.Realm
|
||||
@ -71,7 +70,7 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
|
||||
Timber.w("Event has no room id ${event.eventId}")
|
||||
return@forEach
|
||||
}
|
||||
val isLocalEcho = LocalEchoEventFactory.isLocalEchoId(event.eventId ?: "")
|
||||
val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
|
||||
when (event.type) {
|
||||
EventType.REACTION -> {
|
||||
// we got a reaction!!
|
||||
|
@ -87,7 +87,7 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
|
||||
roomSummaryEntity.membership = membership
|
||||
}
|
||||
|
||||
val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES)
|
||||
val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, filterTypes = PREVIEWABLE_TYPES)
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
|
||||
|
||||
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
|
||||
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.room.prune
|
||||
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.LocalEcho
|
||||
import im.vector.matrix.android.api.session.events.model.UnsignedData
|
||||
import im.vector.matrix.android.internal.database.helper.updateSenderData
|
||||
import im.vector.matrix.android.internal.database.mapper.ContentMapper
|
||||
@ -27,7 +28,6 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||
import im.vector.matrix.android.internal.database.query.findWithSenderMembershipEvent
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import io.realm.Realm
|
||||
@ -59,7 +59,7 @@ internal class DefaultPruneEventTask @Inject constructor(private val monarchy: M
|
||||
// Check that we know this event
|
||||
EventEntity.where(realm, eventId = redactionEvent.eventId ?: "").findFirst() ?: return
|
||||
|
||||
val isLocalEcho = LocalEchoEventFactory.isLocalEchoId(redactionEvent.eventId ?: "")
|
||||
val isLocalEcho = LocalEcho.isLocalEchoId(redactionEvent.eventId ?: "")
|
||||
Timber.v("Redact event for ${redactionEvent.redacts} localEcho=$isLocalEcho")
|
||||
|
||||
val eventToPrune = EventEntity.where(realm, eventId = redactionEvent.redacts).findFirst()
|
||||
|
@ -17,6 +17,7 @@
|
||||
package im.vector.matrix.android.internal.session.room.read
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||
import im.vector.matrix.android.internal.database.model.ReadMarkerEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||
@ -26,7 +27,6 @@ import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.session.sync.ReadReceiptHandler
|
||||
import im.vector.matrix.android.internal.session.sync.RoomFullyReadHandler
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
@ -73,7 +73,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI
|
||||
}
|
||||
|
||||
if (fullyReadEventId != null && isReadMarkerMoreRecent(params.roomId, fullyReadEventId)) {
|
||||
if (LocalEchoEventFactory.isLocalEchoId(fullyReadEventId)) {
|
||||
if (LocalEcho.isLocalEchoId(fullyReadEventId)) {
|
||||
Timber.w("Can't set read marker for local event $fullyReadEventId")
|
||||
} else {
|
||||
markers[READ_MARKER] = fullyReadEventId
|
||||
@ -82,7 +82,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI
|
||||
|
||||
if (readReceiptEventId != null
|
||||
&& !isEventRead(monarchy, userId, params.roomId, readReceiptEventId)) {
|
||||
if (LocalEchoEventFactory.isLocalEchoId(readReceiptEventId)) {
|
||||
if (LocalEcho.isLocalEchoId(readReceiptEventId)) {
|
||||
Timber.w("Can't set read receipt for local event $readReceiptEventId")
|
||||
} else {
|
||||
markers[READ_RECEIPT] = readReceiptEventId
|
||||
|
@ -160,7 +160,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use
|
||||
reaction
|
||||
)
|
||||
)
|
||||
val localId = dummyEventId()
|
||||
val localId = LocalEcho.createLocalEchoId()
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
@ -264,7 +264,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use
|
||||
}
|
||||
|
||||
private fun createEvent(roomId: String, content: Any? = null): Event {
|
||||
val localID = dummyEventId()
|
||||
val localID = LocalEcho.createLocalEchoId()
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
@ -280,10 +280,6 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use
|
||||
return System.currentTimeMillis()
|
||||
}
|
||||
|
||||
private fun dummyEventId(): String {
|
||||
return "$LOCAL_ID_PREFIX${UUID.randomUUID()}"
|
||||
}
|
||||
|
||||
fun createReplyTextEvent(roomId: String, eventReplied: TimelineEvent, replyText: String, autoMarkdown: Boolean): Event? {
|
||||
// Fallbacks and event representation
|
||||
// TODO Add error/warning logs when any of this is null
|
||||
@ -383,7 +379,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use
|
||||
}
|
||||
*/
|
||||
fun createRedactEvent(roomId: String, eventId: String, reason: String?): Event {
|
||||
val localID = dummyEventId()
|
||||
val localID = LocalEcho.createLocalEchoId()
|
||||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
@ -407,8 +403,6 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LOCAL_ID_PREFIX = "local."
|
||||
|
||||
// <mx-reply>
|
||||
// <blockquote>
|
||||
// <a href="https://matrix.to/#/!somewhere:domain.com/$event:domain.com">In reply to</a>
|
||||
@ -419,7 +413,5 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use
|
||||
// </mx-reply>
|
||||
// No whitespace because currently breaks temporary formatted text to Span
|
||||
const val REPLY_PATTERN = """<mx-reply><blockquote><a href="%s">%s</a><a href="%s">%s</a><br />%s</blockquote></mx-reply>%s"""
|
||||
|
||||
fun isLocalEchoId(eventId: String): Boolean = eventId.startsWith(LOCAL_ID_PREFIX)
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,12 @@
|
||||
package im.vector.riotx.core.extensions
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
|
||||
fun TimelineEvent.canReact(): Boolean {
|
||||
// Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment
|
||||
return root.getClearType() == EventType.MESSAGE && root.sendState.isSent() && !root.isRedacted()
|
||||
return root.getClearType() == EventType.MESSAGE && root.sendState == SendState.SYNCED && !root.isRedacted()
|
||||
}
|
||||
|
||||
fun TimelineEvent.displayReadMarker(myUserId: String): Boolean {
|
||||
|
@ -26,7 +26,7 @@ import android.view.animation.AnimationUtils
|
||||
import im.vector.riotx.R
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
private const val DELAY_IN_MS = 1_500L
|
||||
private const val DELAY_IN_MS = 1_000L
|
||||
|
||||
class ReadMarkerView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
@ -59,6 +59,7 @@ import im.vector.matrix.android.api.permalinks.PermalinkFactory
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.message.*
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
@ -994,10 +995,16 @@ class RoomDetailFragment :
|
||||
return
|
||||
}
|
||||
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
|
||||
val firstVisibleItem = timelineEventController.adapter.getModelAtPosition(firstVisibleItemPosition)
|
||||
val nextReadMarkerId = when (firstVisibleItem) {
|
||||
is BaseEventItem -> firstVisibleItem.getEventIds().firstOrNull()
|
||||
else -> null
|
||||
var nextReadMarkerId: String? = null
|
||||
for (itemPosition in firstVisibleItemPosition until lastVisibleItemPosition) {
|
||||
val timelineItem = timelineEventController.adapter.getModelAtPosition(itemPosition)
|
||||
if (timelineItem is BaseEventItem) {
|
||||
val eventId = timelineItem.getEventIds().firstOrNull() ?: continue
|
||||
if (!LocalEcho.isLocalEchoId(eventId)) {
|
||||
nextReadMarkerId = eventId
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextReadMarkerId != null) {
|
||||
roomDetailViewModel.process(RoomDetailActions.SetReadMarkerAction(nextReadMarkerId))
|
||||
|
@ -201,7 +201,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
|
||||
if (canCancel(event)) {
|
||||
add(SimpleAction.Cancel(eventId))
|
||||
}
|
||||
} else {
|
||||
} else if (event.root.sendState == SendState.SYNCED) {
|
||||
if (!event.root.isRedacted()) {
|
||||
if (canReply(event, messageContent)) {
|
||||
add(SimpleAction.Reply(eventId))
|
||||
|
Loading…
Reference in New Issue
Block a user