mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-03 06:30:43 +00:00
Store the user avatar thumbnail in the session database
Add a `userAvatarData` column to the session database, containing the base64 encoded thumbnail of the user avatar. It will allow rendering the avatar of an account without having to use its Matrix client, for instance on the signed out screen, or for other accounts when the homeservers are not federated. The thumbnail is downloaded when the user profile is retrieved or updated, and only if the avatar URL has changed. The profile is now also persisted when received from the own profile subscription. Part of #5571 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+2
@@ -46,4 +46,6 @@ data class SessionData(
|
||||
val userDisplayName: String?,
|
||||
/** The optional avatar URL of the user. */
|
||||
val userAvatarUrl: String?,
|
||||
/** The optional thumbnail of the avatar of the user ([userAvatarUrl]), base64 encoded. */
|
||||
val userAvatarData: String?,
|
||||
)
|
||||
|
||||
+2
-1
@@ -51,8 +51,9 @@ interface SessionStore {
|
||||
* @param sessionId the session to update.
|
||||
* @param displayName the new display name, or `null` when the user has none.
|
||||
* @param avatarUrl the new avatar, or `null` when the user has none.
|
||||
* @param avatarData the thumbnail of the new avatar, base64 encoded, or `null` when the user has none or when it could not be loaded.
|
||||
*/
|
||||
suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?)
|
||||
suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?, avatarData: String?)
|
||||
|
||||
/**
|
||||
* Get the session data matching the userId, or null if not found.
|
||||
|
||||
+3
-1
@@ -84,12 +84,13 @@ class DatabaseSessionStore(
|
||||
lastUsageIndex = result.lastUsageIndex,
|
||||
userDisplayName = result.userDisplayName,
|
||||
userAvatarUrl = result.userAvatarUrl,
|
||||
userAvatarData = result.userAvatarData,
|
||||
).toDbModel()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?) {
|
||||
override suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?, avatarData: String?) {
|
||||
sessionDataMutex.withLock {
|
||||
val result = database.sessionDataQueries.selectByUserId(sessionId)
|
||||
.executeAsOneOrNull()
|
||||
@@ -102,6 +103,7 @@ class DatabaseSessionStore(
|
||||
result.copy(
|
||||
userDisplayName = displayName,
|
||||
userAvatarUrl = avatarUrl,
|
||||
userAvatarData = avatarData,
|
||||
).toDbModel()
|
||||
)
|
||||
}
|
||||
|
||||
+2
@@ -31,6 +31,7 @@ internal fun SessionData.toDbModel(): DbSessionData {
|
||||
lastUsageIndex = lastUsageIndex,
|
||||
userDisplayName = userDisplayName,
|
||||
userAvatarUrl = userAvatarUrl,
|
||||
userAvatarData = userAvatarData,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -52,5 +53,6 @@ internal fun DbSessionData.toApiModel(): SessionData {
|
||||
lastUsageIndex = lastUsageIndex,
|
||||
userDisplayName = userDisplayName,
|
||||
userAvatarUrl = userAvatarUrl,
|
||||
userAvatarData = userAvatarData,
|
||||
)
|
||||
}
|
||||
|
||||
Binary file not shown.
+4
-1
@@ -36,7 +36,10 @@ CREATE TABLE SessionData (
|
||||
-- user display name
|
||||
userDisplayName TEXT,
|
||||
-- user avatar url
|
||||
userAvatarUrl TEXT
|
||||
userAvatarUrl TEXT,
|
||||
-- added in version 13
|
||||
-- user avatar thumbnail data, base64 encoded
|
||||
userAvatarData TEXT
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Migrate DB from version 12
|
||||
-- Add the thumbnail of the user avatar, base64 encoded, so that the avatar can be rendered without a Matrix client.
|
||||
|
||||
ALTER TABLE SessionData ADD COLUMN userAvatarData TEXT;
|
||||
+8
-2
@@ -134,17 +134,18 @@ class DatabaseSessionStoreTest {
|
||||
|
||||
@Test
|
||||
fun `updateUserProfile does nothing if the session is not found`() = runTest {
|
||||
databaseSessionStore.updateUserProfile(aSessionData.userId, "userDisplayName", "userAvatarUrl")
|
||||
databaseSessionStore.updateUserProfile(aSessionData.userId, "userDisplayName", "userAvatarUrl", "userAvatarData")
|
||||
assertThat(database.sessionDataQueries.selectByUserId(aSessionData.userId).executeAsOneOrNull()).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateUserProfile update the data`() = runTest {
|
||||
database.sessionDataQueries.insertSessionData(aSessionData)
|
||||
databaseSessionStore.updateUserProfile(aSessionData.userId, "userDisplayName", "userAvatarUrl")
|
||||
databaseSessionStore.updateUserProfile(aSessionData.userId, "userDisplayName", "userAvatarUrl", "userAvatarData")
|
||||
val updatedSession = database.sessionDataQueries.selectByUserId(aSessionData.userId).executeAsOne()
|
||||
assertThat(updatedSession.userDisplayName).isEqualTo("userDisplayName")
|
||||
assertThat(updatedSession.userAvatarUrl).isEqualTo("userAvatarUrl")
|
||||
assertThat(updatedSession.userAvatarData).isEqualTo("userAvatarData")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -231,6 +232,7 @@ class DatabaseSessionStoreTest {
|
||||
lastUsageIndex = 0,
|
||||
userDisplayName = "userDisplayName",
|
||||
userAvatarUrl = "userAvatarUrl",
|
||||
userAvatarData = "userAvatarData",
|
||||
)
|
||||
val secondSessionData = SessionData(
|
||||
userId = "userId",
|
||||
@@ -249,6 +251,7 @@ class DatabaseSessionStoreTest {
|
||||
lastUsageIndex = 1,
|
||||
userDisplayName = "userDisplayNameAltered",
|
||||
userAvatarUrl = "userAvatarUrlAltered",
|
||||
userAvatarData = "userAvatarDataAltered",
|
||||
)
|
||||
assertThat(firstSessionData.userId).isEqualTo(secondSessionData.userId)
|
||||
assertThat(firstSessionData.loginTimestamp).isNotEqualTo(secondSessionData.loginTimestamp)
|
||||
@@ -273,6 +276,7 @@ class DatabaseSessionStoreTest {
|
||||
assertThat(alteredSession.lastUsageIndex).isEqualTo(firstSessionData.lastUsageIndex)
|
||||
assertThat(alteredSession.userDisplayName).isEqualTo(firstSessionData.userDisplayName)
|
||||
assertThat(alteredSession.userAvatarUrl).isEqualTo(firstSessionData.userAvatarUrl)
|
||||
assertThat(alteredSession.userAvatarData).isEqualTo(firstSessionData.userAvatarData)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -294,6 +298,7 @@ class DatabaseSessionStoreTest {
|
||||
lastUsageIndex = 0,
|
||||
userDisplayName = "userDisplayName",
|
||||
userAvatarUrl = "userAvatarUrl",
|
||||
userAvatarData = "userAvatarData",
|
||||
)
|
||||
val secondSessionData = SessionData(
|
||||
userId = "userIdUnknown",
|
||||
@@ -312,6 +317,7 @@ class DatabaseSessionStoreTest {
|
||||
lastUsageIndex = 1,
|
||||
userDisplayName = "userDisplayNameAltered",
|
||||
userAvatarUrl = "userAvatarUrlAltered",
|
||||
userAvatarData = "userAvatarDataAltered",
|
||||
)
|
||||
assertThat(firstSessionData.userId).isNotEqualTo(secondSessionData.userId)
|
||||
|
||||
|
||||
+1
@@ -30,4 +30,5 @@ internal fun aDbSessionData(
|
||||
lastUsageIndex = 0,
|
||||
userDisplayName = null,
|
||||
userAvatarUrl = null,
|
||||
userAvatarData = null,
|
||||
)
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ import kotlinx.coroutines.flow.map
|
||||
|
||||
class InMemorySessionStore(
|
||||
initialList: List<SessionData> = emptyList(),
|
||||
private val updateUserProfileResult: (String, String?, String?) -> Unit = { _, _, _ -> error("Not implemented") },
|
||||
private val updateUserProfileResult: (String, String?, String?, String?) -> Unit = { _, _, _, _ -> error("Not implemented") },
|
||||
private val setLatestSessionResult: (String) -> Unit = { error("Not implemented") },
|
||||
) : SessionStore {
|
||||
private val sessionDataListFlow = MutableStateFlow(initialList)
|
||||
@@ -56,8 +56,8 @@ class InMemorySessionStore(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?) {
|
||||
updateUserProfileResult(sessionId, displayName, avatarUrl)
|
||||
override suspend fun updateUserProfile(sessionId: String, displayName: String?, avatarUrl: String?, avatarData: String?) {
|
||||
updateUserProfileResult(sessionId, displayName, avatarUrl, avatarData)
|
||||
}
|
||||
|
||||
override suspend fun getSession(sessionId: String): SessionData? {
|
||||
|
||||
+2
@@ -23,6 +23,7 @@ fun aSessionData(
|
||||
lastUsageIndex: Long = 0,
|
||||
userDisplayName: String? = null,
|
||||
userAvatarUrl: String? = null,
|
||||
userAvatarData: String? = null,
|
||||
): SessionData {
|
||||
return SessionData(
|
||||
userId = sessionId,
|
||||
@@ -41,5 +42,6 @@ fun aSessionData(
|
||||
lastUsageIndex = lastUsageIndex,
|
||||
userDisplayName = userDisplayName,
|
||||
userAvatarUrl = userAvatarUrl,
|
||||
userAvatarData = userAvatarData,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user