Merge pull request #7900 from element-hq/feature/bma/settingsMainThreadJank

Fix animation glitches when opening the settings
This commit is contained in:
Benoit Marty
2026-10-13 11:30:36 +02:00
committed by GitHub
3 changed files with 86 additions and 78 deletions
@@ -40,10 +40,7 @@ class PreferencesAccountPresenter(
@Composable @Composable
override fun present(): PreferencesAccountState { override fun present(): PreferencesAccountState {
val matrixUser = matrixClient.userProfile.collectAsState() val matrixUser = matrixClient.userProfile.collectAsState()
LaunchedEffect(Unit) { // Note: no need to force a refresh of the profile here, PreferencesRootPresenter, which embeds this presenter, already does it.
// Force a refresh of the profile
matrixClient.getUserProfile()
}
val showLinkNewDevice by remember { val showLinkNewDevice by remember {
featureFlagService.isFeatureEnabledFlow(FeatureFlags.QrCodeLogin) featureFlagService.isFeatureEnabledFlow(FeatureFlags.QrCodeLogin)
}.collectAsState(initial = false) }.collectAsState(initial = false)
@@ -530,7 +530,7 @@ class RustMatrixClient(
* Store the user profile in the session storage, including a base64 encoded thumbnail of the avatar, * Store the user profile in the session storage, including a base64 encoded thumbnail of the avatar,
* so that the avatar can be rendered without having to use this client. * so that the avatar can be rendered without having to use this client.
*/ */
private suspend fun storeUserProfile(matrixUser: MatrixUser) { private suspend fun storeUserProfile(matrixUser: MatrixUser) = withContext(sessionDispatcher) {
val avatarUrl = matrixUser.avatarUrl val avatarUrl = matrixUser.avatarUrl
val storedSession = sessionStore.getSession(sessionId.value) val storedSession = sessionStore.getSession(sessionId.value)
val avatarData = when { val avatarData = when {
@@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
@@ -51,6 +52,7 @@ class DatabaseSessionStore(
} }
override suspend fun addSession(sessionData: SessionData) { override suspend fun addSession(sessionData: SessionData) {
withContext(dispatchers.io) {
sessionDataMutex.withLock { sessionDataMutex.withLock {
val lastUsageIndex = getLastUsageIndex() val lastUsageIndex = getLastUsageIndex()
database.sessionDataQueries.insertSessionData( database.sessionDataQueries.insertSessionData(
@@ -65,8 +67,10 @@ class DatabaseSessionStore(
) )
} }
} }
}
override suspend fun updateData(sessionData: SessionData) { override suspend fun updateData(sessionData: SessionData) {
withContext(dispatchers.io) {
sessionDataMutex.withLock { sessionDataMutex.withLock {
val result = database.sessionDataQueries.selectByUserId(sessionData.userId) val result = database.sessionDataQueries.selectByUserId(sessionData.userId)
.executeAsOneOrNull() .executeAsOneOrNull()
@@ -74,7 +78,7 @@ class DatabaseSessionStore(
if (result == null) { if (result == null) {
Timber.e("User ${sessionData.userId} not found in session database") Timber.e("User ${sessionData.userId} not found in session database")
return return@withContext
} }
// Copy new data from SDK, but keep application data // Copy new data from SDK, but keep application data
database.sessionDataQueries.updateSession( database.sessionDataQueries.updateSession(
@@ -89,15 +93,17 @@ class DatabaseSessionStore(
) )
} }
} }
}
override suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?, avatarData: String?) { override suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?, avatarData: String?) {
withContext(dispatchers.io) {
sessionDataMutex.withLock { sessionDataMutex.withLock {
val result = database.sessionDataQueries.selectByUserId(sessionId) val result = database.sessionDataQueries.selectByUserId(sessionId)
.executeAsOneOrNull() .executeAsOneOrNull()
?.toApiModel() ?.toApiModel()
if (result == null) { if (result == null) {
Timber.e("User $sessionId not found in session database") Timber.e("User $sessionId not found in session database")
return return@withContext
} }
database.sessionDataQueries.updateSession( database.sessionDataQueries.updateSession(
result.copy( result.copy(
@@ -108,12 +114,14 @@ class DatabaseSessionStore(
) )
} }
} }
}
override suspend fun setLatestSession(sessionId: String) { override suspend fun setLatestSession(sessionId: String) {
withContext(dispatchers.io) {
val latestSession = getLatestSession() val latestSession = getLatestSession()
if (latestSession?.userId == sessionId) { if (latestSession?.userId == sessionId) {
// Already the latest session // Already the latest session
return return@withContext
} }
val lastUsageIndex = latestSession?.lastUsageIndex ?: 0 val lastUsageIndex = latestSession?.lastUsageIndex ?: 0
val result = database.sessionDataQueries.selectByUserId(sessionId) val result = database.sessionDataQueries.selectByUserId(sessionId)
@@ -121,7 +129,7 @@ class DatabaseSessionStore(
?.toApiModel() ?.toApiModel()
if (result == null) { if (result == null) {
Timber.e("User $sessionId not found in session database") Timber.e("User $sessionId not found in session database")
return return@withContext
} }
sessionDataMutex.withLock { sessionDataMutex.withLock {
// Update lastUsageIndex of the session // Update lastUsageIndex of the session
@@ -132,6 +140,7 @@ class DatabaseSessionStore(
) )
} }
} }
}
private fun getLastUsageIndex(): Long { private fun getLastUsageIndex(): Long {
return database.sessionDataQueries.selectLatest() return database.sessionDataQueries.selectLatest()
@@ -140,32 +149,32 @@ class DatabaseSessionStore(
?: -1L ?: -1L
} }
override suspend fun getLatestSession(): SessionData? { override suspend fun getLatestSession(): SessionData? = withContext(dispatchers.io) {
return sessionDataMutex.withLock { sessionDataMutex.withLock {
database.sessionDataQueries.selectLatest() database.sessionDataQueries.selectLatest()
.executeAsOneOrNull() .executeAsOneOrNull()
?.toApiModel() ?.toApiModel()
} }
} }
override suspend fun getSession(sessionId: String): SessionData? { override suspend fun getSession(sessionId: String): SessionData? = withContext(dispatchers.io) {
return sessionDataMutex.withLock { sessionDataMutex.withLock {
database.sessionDataQueries.selectByUserId(sessionId) database.sessionDataQueries.selectByUserId(sessionId)
.executeAsOneOrNull() .executeAsOneOrNull()
?.toApiModel() ?.toApiModel()
} }
} }
override suspend fun getAllSessions(): List<SessionData> { override suspend fun getAllSessions(): List<SessionData> = withContext(dispatchers.io) {
return sessionDataMutex.withLock { sessionDataMutex.withLock {
database.sessionDataQueries.selectAll() database.sessionDataQueries.selectAll()
.executeAsList() .executeAsList()
.map { it.toApiModel() } .map { it.toApiModel() }
} }
} }
override suspend fun numberOfSessions(): Int { override suspend fun numberOfSessions(): Int = withContext(dispatchers.io) {
return sessionDataMutex.withLock { sessionDataMutex.withLock {
database.sessionDataQueries.count() database.sessionDataQueries.count()
.executeAsOneOrNull() .executeAsOneOrNull()
?.toInt() ?.toInt()
@@ -181,8 +190,10 @@ class DatabaseSessionStore(
} }
override suspend fun removeSession(sessionId: String) { override suspend fun removeSession(sessionId: String) {
withContext(dispatchers.io) {
sessionDataMutex.withLock { sessionDataMutex.withLock {
database.sessionDataQueries.removeSession(sessionId) database.sessionDataQueries.removeSession(sessionId)
} }
} }
}
} }