diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt index 4e04cd0ab6..e20deb91cb 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt @@ -40,10 +40,7 @@ class PreferencesAccountPresenter( @Composable override fun present(): PreferencesAccountState { val matrixUser = matrixClient.userProfile.collectAsState() - LaunchedEffect(Unit) { - // Force a refresh of the profile - matrixClient.getUserProfile() - } + // Note: no need to force a refresh of the profile here, PreferencesRootPresenter, which embeds this presenter, already does it. val showLinkNewDevice by remember { featureFlagService.isFeatureEnabledFlow(FeatureFlags.QrCodeLogin) }.collectAsState(initial = false) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index a9eb22cc8b..44b33e74a7 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -519,12 +519,14 @@ class RustMatrixClient( } } - override suspend fun getUserProfile(): Result = getProfile(sessionId) - .onSuccess { matrixUser -> - // Also update our session storage - _userProfile.emit(matrixUser) - storeUserProfile(matrixUser) - } + override suspend fun getUserProfile(): Result = withContext(sessionDispatcher) { + getProfile(sessionId) + .onSuccess { matrixUser -> + // Also update our session storage + _userProfile.emit(matrixUser) + storeUserProfile(matrixUser) + } + } /** * Store the user profile in the session storage, including a base64 encoded thumbnail of the avatar, diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt index f183c42225..304a969f9d 100644 --- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt +++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStore.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext import timber.log.Timber @SingleIn(AppScope::class) @@ -51,85 +52,93 @@ class DatabaseSessionStore( } override suspend fun addSession(sessionData: SessionData) { - sessionDataMutex.withLock { - val lastUsageIndex = getLastUsageIndex() - database.sessionDataQueries.insertSessionData( - sessionData - .copy( - // position value does not really matter, so just use lastUsageIndex + 1 to ensure that - // the value is always greater than value of any existing account - position = lastUsageIndex + 1, - lastUsageIndex = lastUsageIndex + 1, - ) - .toDbModel() - ) + withContext(dispatchers.io) { + sessionDataMutex.withLock { + val lastUsageIndex = getLastUsageIndex() + database.sessionDataQueries.insertSessionData( + sessionData + .copy( + // position value does not really matter, so just use lastUsageIndex + 1 to ensure that + // the value is always greater than value of any existing account + position = lastUsageIndex + 1, + lastUsageIndex = lastUsageIndex + 1, + ) + .toDbModel() + ) + } } } override suspend fun updateData(sessionData: SessionData) { - sessionDataMutex.withLock { - val result = database.sessionDataQueries.selectByUserId(sessionData.userId) - .executeAsOneOrNull() - ?.toApiModel() + withContext(dispatchers.io) { + sessionDataMutex.withLock { + val result = database.sessionDataQueries.selectByUserId(sessionData.userId) + .executeAsOneOrNull() + ?.toApiModel() - if (result == null) { - Timber.e("User ${sessionData.userId} not found in session database") - return + if (result == null) { + Timber.e("User ${sessionData.userId} not found in session database") + return@withContext + } + // Copy new data from SDK, but keep application data + database.sessionDataQueries.updateSession( + sessionData.copy( + loginTimestamp = result.loginTimestamp, + position = result.position, + lastUsageIndex = result.lastUsageIndex, + userDisplayName = result.userDisplayName, + userAvatarUrl = result.userAvatarUrl, + userAvatarData = result.userAvatarData, + ).toDbModel() + ) } - // Copy new data from SDK, but keep application data - database.sessionDataQueries.updateSession( - sessionData.copy( - loginTimestamp = result.loginTimestamp, - position = result.position, - lastUsageIndex = result.lastUsageIndex, - userDisplayName = result.userDisplayName, - userAvatarUrl = result.userAvatarUrl, - userAvatarData = result.userAvatarData, - ).toDbModel() - ) } } override suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?, avatarData: String?) { - sessionDataMutex.withLock { + withContext(dispatchers.io) { + sessionDataMutex.withLock { + val result = database.sessionDataQueries.selectByUserId(sessionId) + .executeAsOneOrNull() + ?.toApiModel() + if (result == null) { + Timber.e("User $sessionId not found in session database") + return@withContext + } + database.sessionDataQueries.updateSession( + result.copy( + userDisplayName = displayName, + userAvatarUrl = avatarUrl, + userAvatarData = avatarData, + ).toDbModel() + ) + } + } + } + + override suspend fun setLatestSession(sessionId: String) { + withContext(dispatchers.io) { + val latestSession = getLatestSession() + if (latestSession?.userId == sessionId) { + // Already the latest session + return@withContext + } + val lastUsageIndex = latestSession?.lastUsageIndex ?: 0 val result = database.sessionDataQueries.selectByUserId(sessionId) .executeAsOneOrNull() ?.toApiModel() if (result == null) { Timber.e("User $sessionId not found in session database") - return + return@withContext + } + sessionDataMutex.withLock { + // Update lastUsageIndex of the session + database.sessionDataQueries.updateSession( + result.copy( + lastUsageIndex = lastUsageIndex + 1, + ).toDbModel() + ) } - database.sessionDataQueries.updateSession( - result.copy( - userDisplayName = displayName, - userAvatarUrl = avatarUrl, - userAvatarData = avatarData, - ).toDbModel() - ) - } - } - - override suspend fun setLatestSession(sessionId: String) { - val latestSession = getLatestSession() - if (latestSession?.userId == sessionId) { - // Already the latest session - return - } - val lastUsageIndex = latestSession?.lastUsageIndex ?: 0 - val result = database.sessionDataQueries.selectByUserId(sessionId) - .executeAsOneOrNull() - ?.toApiModel() - if (result == null) { - Timber.e("User $sessionId not found in session database") - return - } - sessionDataMutex.withLock { - // Update lastUsageIndex of the session - database.sessionDataQueries.updateSession( - result.copy( - lastUsageIndex = lastUsageIndex + 1, - ).toDbModel() - ) } } @@ -140,32 +149,32 @@ class DatabaseSessionStore( ?: -1L } - override suspend fun getLatestSession(): SessionData? { - return sessionDataMutex.withLock { + override suspend fun getLatestSession(): SessionData? = withContext(dispatchers.io) { + sessionDataMutex.withLock { database.sessionDataQueries.selectLatest() .executeAsOneOrNull() ?.toApiModel() } } - override suspend fun getSession(sessionId: String): SessionData? { - return sessionDataMutex.withLock { + override suspend fun getSession(sessionId: String): SessionData? = withContext(dispatchers.io) { + sessionDataMutex.withLock { database.sessionDataQueries.selectByUserId(sessionId) .executeAsOneOrNull() ?.toApiModel() } } - override suspend fun getAllSessions(): List { - return sessionDataMutex.withLock { + override suspend fun getAllSessions(): List = withContext(dispatchers.io) { + sessionDataMutex.withLock { database.sessionDataQueries.selectAll() .executeAsList() .map { it.toApiModel() } } } - override suspend fun numberOfSessions(): Int { - return sessionDataMutex.withLock { + override suspend fun numberOfSessions(): Int = withContext(dispatchers.io) { + sessionDataMutex.withLock { database.sessionDataQueries.count() .executeAsOneOrNull() ?.toInt() @@ -181,8 +190,10 @@ class DatabaseSessionStore( } override suspend fun removeSession(sessionId: String) { - sessionDataMutex.withLock { - database.sessionDataQueries.removeSession(sessionId) + withContext(dispatchers.io) { + sessionDataMutex.withLock { + database.sessionDataQueries.removeSession(sessionId) + } } } }