mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 21:32:34 +00:00
Merge branch 'develop' into feature/fga/timeline-multi-forward
This commit is contained in:
+5
@@ -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.
|
||||
|
||||
+73
@@ -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",
|
||||
)
|
||||
+1
@@ -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 {
|
||||
|
||||
+2
@@ -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
|
||||
|
||||
+89
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user