Merge branch 'develop' into feature/fga/timeline-multi-forward

This commit is contained in:
ganfra
2026-09-29 17:15:40 +02:00
1583 changed files with 15749 additions and 7431 deletions
@@ -326,6 +326,11 @@ interface MatrixClient : ClientUrlContentFetcher {
*/
suspend fun uploadMedia(mimeType: String, data: ByteArray): Result<String>
/**
* Returns the latest [RoomInfo] of a room, if known to the client, or `null` if the room is unknown.
*/
suspend fun getRoomInfo(roomId: RoomId): Result<RoomInfo?>
/**
* Get a room info flow for a given room ID.
* The flow will emit a new value whenever the room info is updated, skipping duplicates, and an empty [Optional] if the room is not found.
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.accountprovider
import androidx.compose.runtime.Immutable
@Immutable
sealed interface AccountProvider {
/**
* An account provider that was input by the user.
*/
data class Generic(
val serverName: String,
) : AccountProvider
/**
* An account provider that is provided by the app.
*/
data class Managed(
val serverName: String,
val baseUrl: String,
val canUseServerName: Boolean,
) : AccountProvider
fun serverNameOrBaseUrl(): String {
return when (this) {
is Generic -> serverName
is Managed -> if (canUseServerName) serverName else baseUrl
}.sanitized()
}
/**
* Return the server name, to be used in the UI.
*/
fun friendlyServerName(): String {
return when (this) {
is Generic -> serverName
is Managed -> serverName
}.sanitized()
}
/**
* The user may reach an allowed account provider by either of its identifiers: the server name it is known by
* (what the user types, e.g. `element.io`) or the base url its client API lives at (e.g. `https://element.ems.host`).
*/
fun matches(other: AccountProvider): Boolean {
return serverNameOrBaseUrl() == other.serverNameOrBaseUrl()
}
/**
* Sanitizes the string with the following rules:
* - Trim any whitespace.
* - Lowercase the string.
* - Removes a https scheme (treating it as implicit).
* - Remove any trailing slashes.
*/
private fun String.sanitized(): String {
return trim()
.lowercase()
// Intentionally continue to show http:// as an indicator (and for history).
.removePrefix("https://")
.removeSuffix("/")
}
}
val matrixOrgAccountProvider = AccountProvider.Generic(
serverName = "matrix.org",
)
@@ -11,6 +11,7 @@ package io.element.android.libraries.matrix.api.core
import io.element.android.libraries.androidutils.metadata.isInDebug
import java.io.Serializable
@kotlinx.serialization.Serializable
@JvmInline
value class RoomId(val value: String) : Serializable {
init {
@@ -19,4 +19,6 @@ data class MatrixUser(
val avatarUrl: String? = null,
val displayedStatus: DisplayedStatus? = null,
val rawStatus: UserStatus? = null,
/** Base64 encoded thumbnail of [avatarUrl], stored locally, used as a fallback when the avatar cannot be loaded. */
val avatarThumbnail: String? = null,
) : Parcelable
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.accountprovider
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class AccountProviderTest {
@Test
fun `serverNameOrBaseUrl of a generic account provider is the server name the user input`() {
assertThat(AccountProvider.Generic("matrix.org").serverNameOrBaseUrl()).isEqualTo("matrix.org")
}
@Test
fun `serverNameOrBaseUrl of a managed account provider is its server name when it can be used`() {
val accountProvider = AccountProvider.Managed(
serverName = "element.io",
baseUrl = "https://element.ems.host",
canUseServerName = true,
)
assertThat(accountProvider.serverNameOrBaseUrl()).isEqualTo("element.io")
}
@Test
fun `serverNameOrBaseUrl of a managed account provider is its base url when the server name cannot be used`() {
val accountProvider = AccountProvider.Managed(
serverName = "element.io",
baseUrl = "https://element.ems.host",
canUseServerName = false,
)
assertThat(accountProvider.serverNameOrBaseUrl()).isEqualTo("element.ems.host")
}
@Test
fun `matrixOrgAccountProvider is known by its server name`() {
assertThat(matrixOrgAccountProvider.serverNameOrBaseUrl()).isEqualTo("matrix.org")
}
@Test
fun `serverNameOrBaseUrl trims, lowercases and drops the implicit https scheme and a trailing slash`() {
assertThat(AccountProvider.Generic(" MATRIX.org ").serverNameOrBaseUrl()).isEqualTo("matrix.org")
assertThat(AccountProvider.Generic("https://matrix.org").serverNameOrBaseUrl()).isEqualTo("matrix.org")
assertThat(AccountProvider.Generic("https://matrix.org/").serverNameOrBaseUrl()).isEqualTo("matrix.org")
}
@Test
fun `serverNameOrBaseUrl keeps an explicit http scheme as an indicator`() {
assertThat(AccountProvider.Generic("http://localhost:8080").serverNameOrBaseUrl()).isEqualTo("http://localhost:8080")
}
@Test
fun `matches ignores the scheme, the case and a trailing slash`() {
val typed = AccountProvider.Generic("Element.io/")
assertThat(typed.matches(AccountProvider.Generic("https://element.io"))).isTrue()
assertThat(
typed.matches(
AccountProvider.Managed(serverName = "element.io", baseUrl = "https://element.ems.host", canUseServerName = true)
)
).isTrue()
}
@Test
fun `matches a managed provider that cannot use its server name only through its base url`() {
val managed = AccountProvider.Managed(
serverName = "element.io",
baseUrl = "https://element.ems.host",
canUseServerName = false,
)
assertThat(AccountProvider.Generic("element.ems.host").matches(managed)).isTrue()
assertThat(AccountProvider.Generic("element.io").matches(managed)).isFalse()
}
@Test
fun `matches is false for a different account provider`() {
val typed = AccountProvider.Generic("element.io")
assertThat(typed.matches(AccountProvider.Generic("matrix.org"))).isFalse()
// A managed provider that can use its server name is not reached through its base url.
assertThat(
typed.matches(
AccountProvider.Managed(serverName = "other.io", baseUrl = "https://element.io", canUseServerName = true)
)
).isFalse()
}
}