Fix issue with local echo

This commit is contained in:
Benoit Marty 2021-03-09 13:55:56 +01:00
parent 0cd728222e
commit 25ea1ba641
5 changed files with 41 additions and 27 deletions

View file

@ -15,6 +15,7 @@ Improvements 🙌:
Bugfix 🐛:
- Try to fix crash about UrlPreview (#2640)
- Be robust if Event.type is missing (#2946)
- Snappier message send status
Translations 🗣:
- All string resources and translations have been moved to the application module. Weblate project for the SDK will be removed.

View file

@ -98,6 +98,19 @@ data class Event(
@Transient
var ageLocalTs: Long? = null
/**
* Copy all fields, including transient fields
*/
fun copyAll(): Event {
return copy().also {
it.mxDecryptionResult = mxDecryptionResult
it.mCryptoError = mCryptoError
it.mCryptoErrorReason = mCryptoErrorReason
it.sendState = sendState
it.ageLocalTs = ageLocalTs
}
}
/**
* Check if event is a state event.
* @return true if event is state event.

View file

@ -27,7 +27,6 @@ import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.internal.database.RealmSessionProvider
import org.matrix.android.sdk.internal.database.asyncTransaction
import org.matrix.android.sdk.internal.database.helper.nextId
import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.mapper.toEntity
@ -45,6 +44,7 @@ import org.matrix.android.sdk.internal.session.room.timeline.TimelineInput
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.util.awaitTransaction
import timber.log.Timber
import java.util.UUID
import javax.inject.Inject
internal class LocalEchoRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
@ -64,7 +64,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private
val eventEntity = event.toEntity(roomId, SendState.UNSENT, System.currentTimeMillis())
val roomMemberHelper = RoomMemberHelper(realm, roomId)
val myUser = roomMemberHelper.getLastRoomMember(senderId)
val localId = TimelineEventEntity.nextId(realm)
val localId = UUID.randomUUID().mostSignificantBits
TimelineEventEntity(localId).also {
it.root = eventEntity
it.eventId = event.eventId

View file

@ -418,27 +418,29 @@ internal class DefaultTimeline(
}
private fun buildSendingEvents(): List<TimelineEvent> {
val builtSendingEvents = ArrayList<TimelineEvent>()
val builtSendingEvents = mutableListOf<TimelineEvent>()
if (hasReachedEnd(Timeline.Direction.FORWARDS) && !hasMoreInCache(Timeline.Direction.FORWARDS)) {
builtSendingEvents.addAll(
uiEchoManager.getInMemorySendingEvents()
.filterEventsWithSettings(settings)
)
uiEchoManager.getInMemorySendingEvents()
.filterSendingEventsTo(builtSendingEvents)
sendingEvents
.map { timelineEventMapper.map(it) }
// Filter out sending event that are not displayable!
.filterEventsWithSettings(settings)
.forEach { timelineEvent ->
if (builtSendingEvents.find { it.eventId == timelineEvent.eventId } == null) {
uiEchoManager.updateSentStateWithUiEcho(timelineEvent)
builtSendingEvents.add(timelineEvent)
}
.filter { timelineEvent ->
builtSendingEvents.none { it.eventId == timelineEvent.eventId }
}
.map { timelineEventMapper.map(it) }
.filterSendingEventsTo(builtSendingEvents)
}
return builtSendingEvents
}
private fun List<TimelineEvent>.filterSendingEventsTo(target: MutableList<TimelineEvent>) {
target.addAll(
// Filter out sending event that are not displayable!
filterEventsWithSettings(settings)
// Get most up to date send state (in memory)
.map { uiEchoManager.updateSentStateWithUiEcho(it) }
)
}
private fun canPaginate(direction: Timeline.Direction): Boolean {
return isReady.get() && !getState(direction).isPaginating && hasMoreToLoad(direction)
}

View file

@ -55,10 +55,6 @@ internal class UIEchoManager(
eventIds.forEach { eventId ->
inMemorySendingEvents.removeAll { eventId == it.eventId }
}
inMemorySendingStates.keys.removeAll { key ->
eventIds.find { it == key } == null
}
inMemoryReactions.forEach { (_, uiEchoData) ->
uiEchoData.removeAll { data ->
// I remove the uiEcho, when the related event is not anymore in the sending list
@ -159,13 +155,14 @@ internal class UIEchoManager(
)
}
fun updateSentStateWithUiEcho(element: TimelineEvent) {
inMemorySendingStates[element.eventId]?.let {
// Timber.v("## ${System.currentTimeMillis()} Send event refresh echo with live state ${it} from state ${element.root.sendState}")
if(element.root.sendState != SendState.SENT) {
element.root.sendState = it
}
}
fun updateSentStateWithUiEcho(timelineEvent: TimelineEvent): TimelineEvent {
if (timelineEvent.root.sendState.isSent()) return timelineEvent
val inMemoryState = inMemorySendingStates[timelineEvent.eventId] ?: return timelineEvent
// Timber.v("## ${System.currentTimeMillis()} Send event refresh echo with live state $inMemoryState from state ${element.root.sendState}")
return timelineEvent.copy(
root = timelineEvent.root.copyAll()
.also { it.sendState = inMemoryState }
)
}
fun onSyncedEvent(transactionId: String?) {
@ -177,5 +174,6 @@ internal class UIEchoManager(
inMemoryReactions.forEach { (_, u) ->
u.filterNot { it.localEchoId == transactionId }
}
inMemorySendingStates.remove(transactionId)
}
}