mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
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.RoomMemberHelper
|
||||
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 timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@ -73,10 +74,9 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||
@UserId private val userId: String,
|
||||
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||
private val roomAvatarResolver: RoomAvatarResolver,
|
||||
private val eventDecryptor: EventDecryptor,
|
||||
// private val crossSigningService: DefaultCrossSigningService,
|
||||
private val roomAccountDataDataSource: RoomAccountDataDataSource,
|
||||
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
|
||||
private val roomSummaryEventDecryptor: RoomSummaryEventDecryptor
|
||||
) {
|
||||
|
||||
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")
|
||||
}
|
||||
else -> {
|
||||
if (root.type == EventType.ENCRYPTED && root.decryptionResultJson == null) {
|
||||
Timber.v("Should decrypt $eventId")
|
||||
tryOrNull {
|
||||
runBlocking { eventDecryptor.decryptEvent(root.asDomain(), "") }
|
||||
}?.let { root.setDecryptionResult(it) }
|
||||
}
|
||||
roomSummaryEventDecryptor.requestDecryption(root.asDomain())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
private val roomSummaryItemFactory: RoomSummaryItemFactory,
|
||||
fontScalePreferences: FontScalePreferences
|
||||
fontScalePreferences: FontScalePreferences,
|
||||
roomSummaryRoomListDiffCallback: RoomSummaryRoomListDiffCallback,
|
||||
) : PagedListEpoxyController<RoomSummary>(
|
||||
// Important it must match the PageList builder notify Looper
|
||||
modelBuildingHandler = createUIHandler()
|
||||
modelBuildingHandler = createUIHandler(),
|
||||
itemDiffCallback = roomSummaryRoomListDiffCallback,
|
||||
) {
|
||||
|
||||
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…
Reference in New Issue
Block a user