Reduce room list placeholder lags
This commit is contained in:
parent
0953bc944d
commit
cba3c270f5
@ -64,6 +64,7 @@ import org.matrix.android.sdk.internal.session.room.accountdata.RoomAccountDataD
|
|||||||
import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
|
import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
||||||
import org.matrix.android.sdk.internal.session.room.relationship.RoomChildRelationInfo
|
import org.matrix.android.sdk.internal.session.room.relationship.RoomChildRelationInfo
|
||||||
|
import org.matrix.android.sdk.internal.session.room.timeline.RoomSummaryEventDecryptor
|
||||||
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
|
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -73,10 +74,9 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||||||
@UserId private val userId: String,
|
@UserId private val userId: String,
|
||||||
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||||
private val roomAvatarResolver: RoomAvatarResolver,
|
private val roomAvatarResolver: RoomAvatarResolver,
|
||||||
private val eventDecryptor: EventDecryptor,
|
|
||||||
// private val crossSigningService: DefaultCrossSigningService,
|
|
||||||
private val roomAccountDataDataSource: RoomAccountDataDataSource,
|
private val roomAccountDataDataSource: RoomAccountDataDataSource,
|
||||||
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
|
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
|
||||||
|
private val roomSummaryEventDecryptor: RoomSummaryEventDecryptor
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun refreshLatestPreviewContent(realm: Realm, roomId: String) {
|
fun refreshLatestPreviewContent(realm: Realm, roomId: String) {
|
||||||
@ -215,12 +215,7 @@ internal class RoomSummaryUpdater @Inject constructor(
|
|||||||
Timber.v("Decryption skipped due to missing root event $eventId")
|
Timber.v("Decryption skipped due to missing root event $eventId")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if (root.type == EventType.ENCRYPTED && root.decryptionResultJson == null) {
|
roomSummaryEventDecryptor.requestDecryption(root.asDomain())
|
||||||
Timber.v("Should decrypt $eventId")
|
|
||||||
tryOrNull {
|
|
||||||
runBlocking { eventDecryptor.decryptEvent(root.asDomain(), "") }
|
|
||||||
}?.let { root.setDecryptionResult(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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.session.room.timeline
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import kotlinx.coroutines.CoroutineName
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||||
|
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.NewSessionListener
|
||||||
|
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.internal.database.model.EventEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@SessionScope
|
||||||
|
internal class RoomSummaryEventDecryptor @Inject constructor(
|
||||||
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
private val cryptoCoroutineScope: CoroutineScope,
|
||||||
|
private val cryptoService: dagger.Lazy<CryptoService>
|
||||||
|
) {
|
||||||
|
|
||||||
|
internal sealed class Message {
|
||||||
|
data class DecryptEvent(val event: Event) : Message()
|
||||||
|
data class NewSessionImported(val sessionId: String) : Message()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val scope: CoroutineScope = CoroutineScope(
|
||||||
|
cryptoCoroutineScope.coroutineContext
|
||||||
|
+ SupervisorJob()
|
||||||
|
+ CoroutineName("RoomSummaryDecryptor")
|
||||||
|
)
|
||||||
|
|
||||||
|
private val channel = Channel<Message>(capacity = 300)
|
||||||
|
|
||||||
|
private val newSessionListener = object : NewSessionListener {
|
||||||
|
override fun onNewSession(roomId: String?, sessionId: String) {
|
||||||
|
scope.launch(coroutineDispatchers.computation) {
|
||||||
|
channel.send(Message.NewSessionImported(sessionId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val unknownSessionsFailure = mutableMapOf<String, MutableSet<Event>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
scope.launch {
|
||||||
|
cryptoService.get().addNewSessionListener(newSessionListener)
|
||||||
|
for (request in channel) {
|
||||||
|
when (request) {
|
||||||
|
is Message.DecryptEvent -> handleDecryptEvent(request.event)
|
||||||
|
is Message.NewSessionImported -> handleNewSessionImported(request.sessionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleNewSessionImported(sessionId: String) {
|
||||||
|
unknownSessionsFailure[sessionId]
|
||||||
|
?.toList()
|
||||||
|
.orEmpty()
|
||||||
|
.also {
|
||||||
|
unknownSessionsFailure[sessionId]?.clear()
|
||||||
|
}.forEach {
|
||||||
|
// post a retry!
|
||||||
|
requestDecryption(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun handleDecryptEvent(event: Event) {
|
||||||
|
if (event.getClearType() != EventType.ENCRYPTED) return
|
||||||
|
val algorithm = event.content?.get("algorithm") as? String
|
||||||
|
if (algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
val result = cryptoService.get().decryptEvent(event, "")
|
||||||
|
// now let's persist the result in database
|
||||||
|
monarchy.writeAsync { realm ->
|
||||||
|
val eventEntity = EventEntity.where(realm, event.eventId.orEmpty()).findFirst()
|
||||||
|
eventEntity?.setDecryptionResult(result)
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.v(failure, "Failed to decrypt event ${event.eventId}")
|
||||||
|
// We don't need to get more details, just mark this session in failures
|
||||||
|
if (failure is MXCryptoError.Base) {
|
||||||
|
monarchy.writeAsync { realm ->
|
||||||
|
EventEntity.where(realm, eventId = event.eventId.orEmpty())
|
||||||
|
.findFirst()
|
||||||
|
?.let {
|
||||||
|
it.decryptionErrorCode = failure.errorType.name
|
||||||
|
it.decryptionErrorReason = failure.technicalMessage.takeIf { it.isNotEmpty() } ?: failure.detailedErrorDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failure.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID
|
||||||
|
|| failure.errorType == MXCryptoError.ErrorType.UNKNOWN_MESSAGE_INDEX) {
|
||||||
|
(event.content["session_id"] as? String)?.let { sessionId ->
|
||||||
|
unknownSessionsFailure.getOrPut(sessionId) { mutableSetOf() }
|
||||||
|
.add(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestDecryption(event: Event) {
|
||||||
|
channel.trySend(Message.DecryptEvent(event))
|
||||||
|
}
|
||||||
|
}
|
@ -32,10 +32,12 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class HomeFilteredRoomsController @Inject constructor(
|
class HomeFilteredRoomsController @Inject constructor(
|
||||||
private val roomSummaryItemFactory: RoomSummaryItemFactory,
|
private val roomSummaryItemFactory: RoomSummaryItemFactory,
|
||||||
fontScalePreferences: FontScalePreferences
|
fontScalePreferences: FontScalePreferences,
|
||||||
|
roomSummaryRoomListDiffCallback: RoomSummaryRoomListDiffCallback,
|
||||||
) : PagedListEpoxyController<RoomSummary>(
|
) : PagedListEpoxyController<RoomSummary>(
|
||||||
// Important it must match the PageList builder notify Looper
|
// Important it must match the PageList builder notify Looper
|
||||||
modelBuildingHandler = createUIHandler()
|
modelBuildingHandler = createUIHandler(),
|
||||||
|
itemDiffCallback = roomSummaryRoomListDiffCallback,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private var roomChangeMembershipStates: Map<String, ChangeMembershipState>? = null
|
private var roomChangeMembershipStates: Map<String, ChangeMembershipState>? = null
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RoomSummaryRoomListDiffCallback @Inject constructor(
|
||||||
|
vectorPreferences: VectorPreferences
|
||||||
|
): DiffUtil.ItemCallback<RoomSummary>() {
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItem: RoomSummary, newItem: RoomSummary): Boolean {
|
||||||
|
return oldItem.roomId == newItem.roomId
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: RoomSummary, newItem: RoomSummary): Boolean {
|
||||||
|
// for this use case we can test less things
|
||||||
|
if (oldItem.roomId != newItem.roomId) return false
|
||||||
|
if (oldItem.displayName != newItem.displayName) return false
|
||||||
|
if (oldItem.name != newItem.name) return false
|
||||||
|
if (oldItem.topic != newItem.topic) return false
|
||||||
|
if (oldItem.avatarUrl != newItem.avatarUrl) return false
|
||||||
|
if (oldItem.canonicalAlias != newItem.canonicalAlias) return false
|
||||||
|
if (oldItem.aliases != newItem.aliases) return false
|
||||||
|
if (oldItem.isDirect != newItem.isDirect) return false
|
||||||
|
if (oldItem.directUserPresence != newItem.directUserPresence) return false
|
||||||
|
if (oldItem.latestPreviewableEvent != newItem.latestPreviewableEvent) return false
|
||||||
|
if (oldItem.notificationCount != newItem.notificationCount) return false
|
||||||
|
if (oldItem.highlightCount != newItem.highlightCount) return false
|
||||||
|
if (oldItem.threadNotificationCount != newItem.threadNotificationCount) return false
|
||||||
|
if (oldItem.threadHighlightCount != newItem.threadHighlightCount) return false
|
||||||
|
if (oldItem.hasUnreadMessages != newItem.hasUnreadMessages) return false
|
||||||
|
if (oldItem.userDrafts != newItem.userDrafts) return false
|
||||||
|
if (oldItem.isEncrypted != newItem.isEncrypted) return false
|
||||||
|
if (oldItem.typingUsers != newItem.typingUsers) return false
|
||||||
|
if (oldItem.hasFailedSending != newItem.hasFailedSending) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user