mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
Move the :libraries:wellknown logic into enterprise modules (#7429)
* Extract `IsEnterpriseBuild` use case Having it inside `EnterpriseService` made having DI cycles with the `BuildMeta` provider too easy * Rename `EnterpriseService.defaultHomeserverList()` to `homeserverAllowList()` This seems more aligned with the way this list works * Move most of the logic from `:libraries:wellknown` to `:enterprise:feature:enterprise`, both `shared` and `impl` modules Ideally I would have added everything into `impl`, but some of the classes needed to be shared between the different `:enterprise:features` modules, and those are in the `shared` module, lacking a better name/strategy * Add `EnterpriseService.isElementProEnforced` With this, we don't need to provide the `RemoteEnterpriseConfig` anymore to any consumers, everything goes through `EnterpriseService` or other providers * Remove `EnterpriseService.overriddenElementWellKnown` This leaks the remote enterprise config/element well known contents to the app in a public interface. * Create `CustomMapTilerConfigProvider` to avoid leaking the `RemoteEnterpriseConfig` in public APIs This commit also starts moving some of the well-known related values to the enterprise modules * Add missing docs to `EnterpriseService` and `SessionEnterpriseService` * Fix tests * Fix lint issues * Bump enterprise module
This commit is contained in:
committed by
GitHub
parent
f94566e44f
commit
8b2c207728
+13
-13
@@ -12,7 +12,6 @@ import androidx.compose.ui.graphics.Color
|
||||
import io.element.android.compound.colors.SemanticColorsLightDark
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
@@ -21,9 +20,6 @@ import kotlinx.coroutines.flow.Flow
|
||||
* On a standard build this reports permissive defaults, so callers do not need to branch on the build type themselves.
|
||||
*/
|
||||
interface EnterpriseService {
|
||||
/** Whether this build is an enterprise one; `false` for the public app. */
|
||||
val isEnterpriseBuild: Boolean
|
||||
|
||||
/**
|
||||
* Whether the given session belongs to an enterprise deployment, which can be true even on a standard build.
|
||||
*
|
||||
@@ -41,17 +37,26 @@ interface EnterpriseService {
|
||||
suspend fun tweakMasUrl(url: String, homeserver: String, urlContentFetcher: UrlContentFetcher): String
|
||||
|
||||
/**
|
||||
* The homeservers the user is allowed to sign in to; an empty list, or one containing [ANY_ACCOUNT_PROVIDER], means no restriction.
|
||||
* Returns the list of homeservers the user is allowed to sign in to.
|
||||
*
|
||||
* If the list is empty or contains the special value [ANY_ACCOUNT_PROVIDER], the user is allowed to sign in to any homeserver.
|
||||
*/
|
||||
fun defaultHomeserverList(): List<String>
|
||||
fun homeserverAllowList(): List<String>
|
||||
|
||||
/**
|
||||
* Whether the user is allowed to sign in to a given homeserver, according to [defaultHomeserverList].
|
||||
* Whether the user is allowed to sign in to a given homeserver, according to [homeserverAllowList].
|
||||
*
|
||||
* @param homeserverUrl the server the user is trying to use.
|
||||
*/
|
||||
suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean
|
||||
|
||||
/**
|
||||
* Whether the given homeserver enforces the use of Element Pro or a derived app.
|
||||
*
|
||||
* @param homeserverUrl the homeserver to check.
|
||||
*/
|
||||
suspend fun isElementProEnforced(homeserverUrl: String): Boolean
|
||||
|
||||
/**
|
||||
* Override the brand color.
|
||||
* @param sessionId the session to override the brand color for, or null to set the brand color to use when there is no session.
|
||||
@@ -94,11 +99,6 @@ interface EnterpriseService {
|
||||
*/
|
||||
fun getNoisyNotificationChannelId(sessionId: SessionId): String?
|
||||
|
||||
/**
|
||||
* Gets the overridden Element Well-Known data if it has been set, or null if not set.
|
||||
*/
|
||||
fun overriddenElementWellKnown(): ElementWellKnown?
|
||||
|
||||
/**
|
||||
* Gets the Element Server Suite (ESS) config endpoint URL for the given domain.
|
||||
* Returns `null` when this build does not read its configuration from an ESS deployment.
|
||||
@@ -113,7 +113,7 @@ interface EnterpriseService {
|
||||
}
|
||||
|
||||
fun EnterpriseService.canConnectToAnyHomeserver(): Boolean {
|
||||
return defaultHomeserverList().let {
|
||||
return homeserverAllowList().let {
|
||||
it.isEmpty() || it.contains(EnterpriseService.ANY_ACCOUNT_PROVIDER)
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.features.enterprise.api
|
||||
|
||||
/**
|
||||
* A use case to check if this build of the app is an enterprise build.
|
||||
*/
|
||||
fun interface IsEnterpriseBuild {
|
||||
/**
|
||||
* Returns `true` if this build of the app is an enterprise build, `false` otherwise.
|
||||
*/
|
||||
operator fun invoke(): Boolean
|
||||
}
|
||||
+3
-3
@@ -14,6 +14,9 @@ package io.element.android.features.enterprise.api
|
||||
* [init] must have run before the other members return meaningful answers.
|
||||
*/
|
||||
interface SessionEnterpriseService {
|
||||
/** Loads the deployment configuration of this session; to be called once when the session starts. */
|
||||
suspend fun init()
|
||||
|
||||
/** Whether Element Call may be used on this session, which a deployment can turn off. */
|
||||
suspend fun isElementCallAvailable(): Boolean
|
||||
|
||||
@@ -26,7 +29,4 @@ interface SessionEnterpriseService {
|
||||
|
||||
/** Whether the homeserver forbids creating encrypted rooms, in which case the app must not offer the option. */
|
||||
suspend fun isEncryptionDisabledByHomeserver(): Boolean
|
||||
|
||||
/** Loads the deployment configuration of this session; to be called once when the session starts. */
|
||||
suspend fun init()
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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.features.enterprise.api.remoteconfig
|
||||
|
||||
/**
|
||||
* A provider of a runtime-fetched MapTiler configuration, which can be used to override the default MapTiler configuration.
|
||||
*/
|
||||
fun interface CustomMapTilerConfigProvider {
|
||||
suspend fun get(): Result<MapTilerConfig?>
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.features.enterprise.api.remoteconfig
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
/**
|
||||
* A `MapTiler` configuration received from the server. This configuration is used to display maps in the app.
|
||||
*/
|
||||
@Immutable
|
||||
data class MapTilerConfig(
|
||||
/** The API key to use with MapTiler. This is always not null, but can be empty/blank. */
|
||||
val apiKey: String,
|
||||
/** The style ID to use for light mode. This is optional and can be null. */
|
||||
val lightStyleId: String?,
|
||||
/** The style ID to use for light mode. This is optional and can be null. */
|
||||
val darkStyleId: String?,
|
||||
/** The base URL to use for MapTiler. This is optional and can be null. */
|
||||
val baseUrl: String?,
|
||||
)
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* 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.features.enterprise.api.remoteconfig
|
||||
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
|
||||
/**
|
||||
* Typealias for the well-known configuration used for enterprise features.
|
||||
*
|
||||
* This will allow for easier refactoring in the future when we'll want to move as much of its logic as possible to this module.
|
||||
*/
|
||||
typealias RemoteEnterpriseConfig = ElementWellKnown
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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.features.enterprise.api.remoteconfig
|
||||
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
|
||||
/**
|
||||
* Wrapper to fetch the remote enterprise configuration for a given [SessionId], either from a local cache or from a remote source.
|
||||
*/
|
||||
interface RemoteEnterpriseConfigProvider {
|
||||
/**
|
||||
* Returns the configuration of a session, served from the cache when possible.
|
||||
* A stale entry is reported as outdated while a refresh runs in the background, so this rarely waits on the network.
|
||||
*
|
||||
* @param sessionId the session whose configuration is requested.
|
||||
*/
|
||||
suspend fun get(sessionId: SessionId): WellknownRetrieverResult<RemoteEnterpriseConfig>
|
||||
|
||||
/**
|
||||
* Creates a provider, which needs a fetcher because the configuration is read over HTTP.
|
||||
*/
|
||||
interface Factory {
|
||||
/**
|
||||
* @param urlContentFetcher used to perform the request; a client that is not authenticated yet also works.
|
||||
*/
|
||||
fun create(urlContentFetcher: UrlContentFetcher): RemoteEnterpriseConfigProvider
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.features.enterprise.api.remoteconfig
|
||||
|
||||
sealed interface RemoteEnterpriseConfigResult<out T> {
|
||||
/**
|
||||
* Well-known data has been successfully retrieved.
|
||||
*/
|
||||
data class Success<out T>(val data: T) : RemoteEnterpriseConfigResult<T>
|
||||
|
||||
/**
|
||||
* Well-known data has been retrieved from the local cache but is outdated and a manual refresh has been launched.
|
||||
*/
|
||||
data class Outdated<out T>(val data: T) : RemoteEnterpriseConfigResult<T>
|
||||
|
||||
/**
|
||||
* Well-known data is not found (file does not exist server side, we got a 404).
|
||||
*/
|
||||
data object NotFound : RemoteEnterpriseConfigResult<Nothing>
|
||||
|
||||
/**
|
||||
* Any other error.
|
||||
*/
|
||||
data class Error(val exception: Exception) : RemoteEnterpriseConfigResult<Nothing>
|
||||
|
||||
fun dataOrNull(): T? = when (this) {
|
||||
is Success<T> -> data
|
||||
is Outdated<T> -> data
|
||||
is Error -> null
|
||||
NotFound -> null
|
||||
}
|
||||
|
||||
fun upToDateDataOrNull(): T? = when (this) {
|
||||
is Success<T> -> data
|
||||
is Outdated<T> -> null
|
||||
is Error -> null
|
||||
NotFound -> null
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -16,18 +16,16 @@ import io.element.android.features.enterprise.api.BugReportUrl
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultEnterpriseService : EnterpriseService {
|
||||
override val isEnterpriseBuild = false
|
||||
|
||||
override suspend fun isEnterpriseUser(sessionId: SessionId) = false
|
||||
override suspend fun tweakMasUrl(url: String, homeserver: String, urlContentFetcher: UrlContentFetcher) = url
|
||||
override fun defaultHomeserverList(): List<String> = emptyList()
|
||||
override fun homeserverAllowList(): List<String> = emptyList()
|
||||
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true
|
||||
override suspend fun isElementProEnforced(homeserverUrl: String): Boolean = false
|
||||
|
||||
override suspend fun overrideBrandColor(sessionId: SessionId?, brandColor: String?) = Unit
|
||||
|
||||
@@ -48,7 +46,5 @@ class DefaultEnterpriseService : EnterpriseService {
|
||||
|
||||
override fun getNoisyNotificationChannelId(sessionId: SessionId): String? = null
|
||||
|
||||
override fun overriddenElementWellKnown(): ElementWellKnown? = null
|
||||
|
||||
override fun essConfigEndpointUrl(domain: String): String? = null
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.features.enterprise.impl
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.enterprise.api.IsEnterpriseBuild
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultIsEnterpriseBuild : IsEnterpriseBuild {
|
||||
override fun invoke(): Boolean = false
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.features.enterprise.impl.remoteconfig
|
||||
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultCustomMapTilerConfigProvider : CustomMapTilerConfigProvider {
|
||||
override suspend fun get(): Result<MapTilerConfig?> = Result.success(null)
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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.features.enterprise.impl.remoteconfig
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfig
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultRemoteEnterpriseConfigProvider : RemoteEnterpriseConfigProvider {
|
||||
override suspend fun get(sessionId: SessionId): WellknownRetrieverResult<RemoteEnterpriseConfig> {
|
||||
return WellknownRetrieverResult.NotFound
|
||||
}
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class Factory : RemoteEnterpriseConfigProvider.Factory {
|
||||
override fun create(urlContentFetcher: UrlContentFetcher): RemoteEnterpriseConfigProvider {
|
||||
return DefaultRemoteEnterpriseConfigProvider()
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-8
@@ -19,15 +19,9 @@ import org.junit.Test
|
||||
|
||||
class DefaultEnterpriseServiceTest {
|
||||
@Test
|
||||
fun `isEnterpriseBuild is false`() {
|
||||
fun homeserverWhitelist() {
|
||||
val defaultEnterpriseService = DefaultEnterpriseService()
|
||||
assertThat(defaultEnterpriseService.isEnterpriseBuild).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `defaultHomeserverList should return empty list`() {
|
||||
val defaultEnterpriseService = DefaultEnterpriseService()
|
||||
assertThat(defaultEnterpriseService.defaultHomeserverList()).isEmpty()
|
||||
assertThat(defaultEnterpriseService.homeserverAllowList()).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+6
-8
@@ -14,7 +14,6 @@ import io.element.android.features.enterprise.api.BugReportUrl
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -22,7 +21,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class FakeEnterpriseService(
|
||||
override val isEnterpriseBuild: Boolean = false,
|
||||
private val isEnterpriseUserResult: (SessionId) -> Boolean = { lambdaError() },
|
||||
private val defaultHomeserverListResult: () -> List<String> = { emptyList() },
|
||||
private val isAllowedToConnectToHomeserverResult: (String) -> Boolean = { lambdaError() },
|
||||
@@ -33,8 +31,8 @@ class FakeEnterpriseService(
|
||||
private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() },
|
||||
private val getNoisyNotificationChannelIdResult: (SessionId?) -> String? = { lambdaError() },
|
||||
private val tweakMasUrlResult: (String, String, UrlContentFetcher) -> String = { _, _, _ -> lambdaError() },
|
||||
private val overrideWellKnownResult: () -> ElementWellKnown? = { lambdaError() },
|
||||
private val essConfigEndpointUrlResult: (String) -> String = { lambdaError() },
|
||||
private val isElementProEnforcedResult: (String) -> Boolean = { lambdaError() },
|
||||
) : EnterpriseService {
|
||||
private val brandColorState = MutableStateFlow(initialBrandColor)
|
||||
private val semanticColorsState = MutableStateFlow(initialSemanticColors)
|
||||
@@ -47,7 +45,7 @@ class FakeEnterpriseService(
|
||||
tweakMasUrlResult(url, homeserver, urlContentFetcher)
|
||||
}
|
||||
|
||||
override fun defaultHomeserverList(): List<String> {
|
||||
override fun homeserverAllowList(): List<String> {
|
||||
return defaultHomeserverListResult()
|
||||
}
|
||||
|
||||
@@ -55,6 +53,10 @@ class FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult(homeserverUrl)
|
||||
}
|
||||
|
||||
override suspend fun isElementProEnforced(homeserverUrl: String): Boolean = simulateLongTask {
|
||||
isElementProEnforcedResult(homeserverUrl)
|
||||
}
|
||||
|
||||
override suspend fun overrideBrandColor(sessionId: SessionId?, brandColor: String?) = simulateLongTask {
|
||||
overrideBrandColorResult(sessionId, brandColor)
|
||||
}
|
||||
@@ -84,10 +86,6 @@ class FakeEnterpriseService(
|
||||
return getNoisyNotificationChannelIdResult(sessionId)
|
||||
}
|
||||
|
||||
override fun overriddenElementWellKnown(): ElementWellKnown? {
|
||||
return overrideWellKnownResult()
|
||||
}
|
||||
|
||||
override fun essConfigEndpointUrl(domain: String): String {
|
||||
return essConfigEndpointUrlResult(domain)
|
||||
}
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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.features.enterprise.test.remoteconfig
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfig
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
|
||||
class FakeRemoteEnterpriseConfigProvider(
|
||||
private val getResult: (SessionId) -> WellknownRetrieverResult<RemoteEnterpriseConfig> = { WellknownRetrieverResult.NotFound }
|
||||
) : RemoteEnterpriseConfigProvider {
|
||||
override suspend fun get(sessionId: SessionId): WellknownRetrieverResult<RemoteEnterpriseConfig> {
|
||||
return getResult(sessionId)
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* 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.features.enterprise.test.remoteconfig
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.libraries.matrix.api.UrlContentFetcher
|
||||
|
||||
class FakeRemoteEnterpriseConfigProviderFactory(
|
||||
private val remoteEnterpriseConfigProvider: RemoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(),
|
||||
) : RemoteEnterpriseConfigProvider.Factory {
|
||||
override fun create(urlContentFetcher: UrlContentFetcher): RemoteEnterpriseConfigProvider = remoteEnterpriseConfigProvider
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.features.enterprise.test.remoteconfig
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
|
||||
fun aMapTilerConfig(
|
||||
apiKey: String = "test_api_key",
|
||||
baseUrl: String? = null,
|
||||
lightStyleId: String? = null,
|
||||
darkStyleId: String? = null,
|
||||
) = MapTilerConfig(
|
||||
apiKey = apiKey,
|
||||
baseUrl = baseUrl,
|
||||
lightStyleId = lightStyleId,
|
||||
darkStyleId = darkStyleId,
|
||||
)
|
||||
@@ -71,6 +71,7 @@ dependencies {
|
||||
implementation(projects.libraries.matrixui)
|
||||
implementation(projects.libraries.uiStrings)
|
||||
implementation(projects.libraries.wellknown.api)
|
||||
implementation(projects.features.enterprise.api)
|
||||
implementation(libs.coil.compose)
|
||||
implementation(libs.datetime)
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
package io.element.android.features.location.api
|
||||
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
|
||||
/**
|
||||
* Provides a [MapTilerConfig] for the MapLibre maps.
|
||||
|
||||
+1
-1
@@ -37,6 +37,7 @@ import coil3.compose.rememberAsyncImagePainter
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.SuccessResult
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.api.internal.StaticMapPlaceholder
|
||||
import io.element.android.features.location.api.internal.centerBottomEdge
|
||||
import io.element.android.features.location.api.internal.rememberStaticMapBuilder
|
||||
@@ -45,7 +46,6 @@ import io.element.android.libraries.designsystem.components.PinVariant
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
|
||||
/**
|
||||
* Shows a static map image downloaded via a third party service's static maps API.
|
||||
|
||||
+1
-1
@@ -8,8 +8,8 @@
|
||||
|
||||
package io.element.android.features.location.api.internal
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.api.BuildConfig
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -10,8 +10,8 @@
|
||||
|
||||
package io.element.android.features.location.api.internal
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.api.BuildConfig
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
|
||||
internal class MapTilerTileServerStyleUriBuilder(
|
||||
private val baseUrl: String,
|
||||
|
||||
+1
-2
@@ -10,8 +10,7 @@ package io.element.android.features.location.api.internal
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
/**
|
||||
* Builds an URL for a 3rd party service provider static maps API.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ package io.element.android.features.location.api.internal
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
|
||||
/**
|
||||
* Builds a style URI for a MapLibre compatible tile server.
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
package io.element.android.features.location.api.internal
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import org.junit.Test
|
||||
|
||||
class MapTilerTileServerStyleUriBuilderTest {
|
||||
|
||||
+1
-1
@@ -43,6 +43,7 @@ import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.max
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.api.internal.rememberTileStyleUrl
|
||||
import io.element.android.features.location.impl.common.MapDefaults
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
@@ -50,7 +51,6 @@ import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.designsystem.text.toDp
|
||||
import io.element.android.libraries.designsystem.theme.components.BottomSheetScaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import org.maplibre.compose.camera.CameraState
|
||||
import org.maplibre.compose.camera.rememberCameraState
|
||||
import org.maplibre.compose.map.MapOptions
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@ import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import im.vector.app.features.analytics.plan.Composer
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
|
||||
import io.element.android.features.location.api.live.ActiveLiveLocationShareManager
|
||||
import io.element.android.features.location.impl.common.LocationConstraintsCheck
|
||||
import io.element.android.features.location.impl.common.MapDefaults
|
||||
@@ -73,7 +73,7 @@ class ShareLocationPresenter(
|
||||
private val liveLocationShareManager: ActiveLiveLocationShareManager,
|
||||
private val liveLocationStore: LiveLocationStore,
|
||||
private val userLocationStateFactory: UserLocationState.Factory,
|
||||
private val remoteEnterpriseConfigProvider: RemoteEnterpriseConfigProvider,
|
||||
private val customMapTilerConfigProvider: CustomMapTilerConfigProvider,
|
||||
) : Presenter<ShareLocationState> {
|
||||
@AssistedFactory
|
||||
fun interface Factory {
|
||||
@@ -96,7 +96,7 @@ class ShareLocationPresenter(
|
||||
val currentUser by client.userProfile.collectAsState()
|
||||
val customMapConfig by produceState(AsyncData.Loading()) {
|
||||
// Ignore errors
|
||||
value = AsyncData.Success(remoteEnterpriseConfigProvider.get(client.sessionId).dataOrNull()?.mapTilerConfig)
|
||||
value = AsyncData.Success(customMapTilerConfigProvider.get().getOrNull())
|
||||
}
|
||||
val sendLiveLocationPermissions by room.permissionsAsState(SendLiveLocationPermissions.DEFAULT) { perms ->
|
||||
perms.sendLiveLocationPermissions()
|
||||
|
||||
+1
-1
@@ -8,12 +8,12 @@
|
||||
|
||||
package io.element.android.features.location.impl.share
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||
import io.element.android.features.location.impl.common.userlocation.UserLocationState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class ShareLocationState(
|
||||
|
||||
+1
-1
@@ -9,13 +9,13 @@
|
||||
package io.element.android.features.location.impl.share
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||
import io.element.android.features.location.impl.common.userlocation.UserLocationState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
+5
-6
@@ -22,7 +22,7 @@ import androidx.compose.runtime.setValue
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.api.ShowLocationMode
|
||||
import io.element.android.features.location.api.live.ActiveLiveLocationShareManager
|
||||
@@ -47,7 +47,6 @@ import io.element.android.libraries.dateformatter.api.DateFormatter
|
||||
import io.element.android.libraries.dateformatter.api.DateFormatterMode
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.getBestName
|
||||
import io.element.android.libraries.matrix.api.room.joinedRoomMembers
|
||||
@@ -58,18 +57,18 @@ import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@AssistedInject class ShowLocationPresenter(
|
||||
@AssistedInject
|
||||
class ShowLocationPresenter(
|
||||
@Assisted private val mode: ShowLocationMode,
|
||||
permissionsPresenterFactory: PermissionsPresenter.Factory,
|
||||
private val locationActions: LocationActions,
|
||||
private val buildMeta: BuildMeta,
|
||||
private val dateFormatter: DateFormatter,
|
||||
private val stringProvider: StringProvider,
|
||||
private val sessionId: SessionId,
|
||||
private val joinedRoom: JoinedRoom,
|
||||
private val liveLocationShareManager: ActiveLiveLocationShareManager,
|
||||
private val userLocationStateFactory: UserLocationState.Factory,
|
||||
private val remoteEnterpriseConfigProvider: RemoteEnterpriseConfigProvider,
|
||||
private val customMapTilerConfigProvider: CustomMapTilerConfigProvider,
|
||||
) : Presenter<ShowLocationState> {
|
||||
@AssistedFactory fun interface Factory {
|
||||
fun create(mode: ShowLocationMode): ShowLocationPresenter
|
||||
@@ -89,7 +88,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
val customMapTilerConfig by produceState(AsyncData.Loading()) {
|
||||
// Ignore errors
|
||||
value = AsyncData.Success(remoteEnterpriseConfigProvider.get(sessionId).dataOrNull()?.mapTilerConfig)
|
||||
value = AsyncData.Success(customMapTilerConfigProvider.get().getOrNull())
|
||||
}
|
||||
|
||||
fun checkLocationConstraints() {
|
||||
|
||||
+1
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package io.element.android.features.location.impl.show
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||
import io.element.android.features.location.impl.common.ui.LocationMarkerData
|
||||
@@ -17,7 +18,6 @@ import io.element.android.libraries.designsystem.components.PinVariant
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class ShowLocationState(
|
||||
|
||||
+1
-1
@@ -9,6 +9,7 @@
|
||||
package io.element.android.features.location.impl.show
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||
import io.element.android.features.location.impl.common.userlocation.UserLocationState
|
||||
@@ -18,7 +19,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.preview.USER_NAME_ALICE
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.wellknown.api.MapTilerConfig
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
class ShowLocationStateProvider : PreviewParameterProvider<ShowLocationState> {
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@ package io.element.android.features.location.impl.share
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.enterprise.test.remoteconfig.FakeRemoteEnterpriseConfigProvider
|
||||
import io.element.android.features.location.impl.common.FakeUserLocationStateFactory
|
||||
import io.element.android.features.location.impl.common.actions.FakeLocationActions
|
||||
import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter
|
||||
@@ -59,7 +58,7 @@ class DefaultShareLocationEntryPointTest {
|
||||
sessionId = room.sessionId,
|
||||
),
|
||||
userLocationStateFactory = FakeUserLocationStateFactory(),
|
||||
remoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(),
|
||||
customMapTilerConfigProvider = { Result.success(null) },
|
||||
)
|
||||
},
|
||||
analyticsService = FakeAnalyticsService(),
|
||||
|
||||
+5
-10
@@ -19,8 +19,8 @@ import app.cash.turbine.ReceiveTurbine
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.Composer
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.features.enterprise.test.remoteconfig.FakeRemoteEnterpriseConfigProvider
|
||||
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
|
||||
import io.element.android.features.enterprise.test.remoteconfig.aMapTilerConfig
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.impl.aPermissionsState
|
||||
import io.element.android.features.location.impl.common.FakeUserLocationStateFactory
|
||||
@@ -32,8 +32,6 @@ import io.element.android.features.location.impl.common.ui.LocationConstraintsDi
|
||||
import io.element.android.features.location.impl.live.LiveLocationStore
|
||||
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
|
||||
import io.element.android.features.messages.test.FakeMessageComposerContext
|
||||
import io.element.android.features.wellknown.test.aMapTilerConfig
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.dateformatter.test.FakeDurationFormatter
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
@@ -55,7 +53,6 @@ import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermiss
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.preferences.api.store.PreferenceDataStoreFactory
|
||||
import io.element.android.libraries.preferences.test.FakePreferenceDataStoreFactory
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
@@ -92,7 +89,7 @@ class ShareLocationPresenterTest {
|
||||
liveLocationShareManager: FakeActiveLiveLocationShareManager = FakeActiveLiveLocationShareManager(),
|
||||
liveLocationStore: LiveLocationStore = createLiveLocationStore(sessionId = joinedRoom.sessionId),
|
||||
client: FakeMatrixClient = fakeMatrixClient,
|
||||
remoteEnterpriseConfigProvider: RemoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(),
|
||||
customMapTilerConfigProvider: () -> Result<MapTilerConfig?> = { Result.success(null) },
|
||||
): ShareLocationPresenter = ShareLocationPresenter(
|
||||
permissionsPresenterFactory = { fakePermissionsPresenter },
|
||||
room = joinedRoom,
|
||||
@@ -106,7 +103,7 @@ class ShareLocationPresenterTest {
|
||||
liveLocationShareManager = liveLocationShareManager,
|
||||
liveLocationStore = liveLocationStore,
|
||||
userLocationStateFactory = FakeUserLocationStateFactory(),
|
||||
remoteEnterpriseConfigProvider = remoteEnterpriseConfigProvider,
|
||||
customMapTilerConfigProvider = customMapTilerConfigProvider,
|
||||
)
|
||||
|
||||
@Test
|
||||
@@ -134,9 +131,7 @@ class ShareLocationPresenterTest {
|
||||
client = FakeMatrixClient(
|
||||
sessionId = A_USER_ID,
|
||||
),
|
||||
remoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(
|
||||
getResult = { WellknownRetrieverResult.Success(anElementWellKnown(mapTilerConfig = mapTilerConfig)) }
|
||||
)
|
||||
customMapTilerConfigProvider = { Result.success(mapTilerConfig) }
|
||||
)
|
||||
shareLocationPresenter.test {
|
||||
val state = awaitItem()
|
||||
|
||||
+1
-4
@@ -11,7 +11,6 @@ package io.element.android.features.location.impl.show
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.enterprise.test.remoteconfig.FakeRemoteEnterpriseConfigProvider
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.api.ShowLocationEntryPoint
|
||||
import io.element.android.features.location.api.ShowLocationMode
|
||||
@@ -21,7 +20,6 @@ import io.element.android.features.location.impl.common.permissions.FakePermissi
|
||||
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
|
||||
import io.element.android.libraries.dateformatter.test.FakeDateFormatter
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
@@ -51,10 +49,9 @@ class DefaultShowLocationEntryPointTest {
|
||||
dateFormatter = FakeDateFormatter(),
|
||||
stringProvider = FakeStringProvider(),
|
||||
joinedRoom = joinedRoom,
|
||||
sessionId = A_SESSION_ID,
|
||||
liveLocationShareManager = FakeActiveLiveLocationShareManager(),
|
||||
userLocationStateFactory = FakeUserLocationStateFactory(),
|
||||
remoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(),
|
||||
customMapTilerConfigProvider = { Result.success(null) },
|
||||
)
|
||||
},
|
||||
analyticsService = FakeAnalyticsService(),
|
||||
|
||||
+6
-22
@@ -12,7 +12,8 @@ import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.enterprise.test.remoteconfig.FakeRemoteEnterpriseConfigProvider
|
||||
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
|
||||
import io.element.android.features.enterprise.test.remoteconfig.aMapTilerConfig
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.api.ShowLocationMode
|
||||
import io.element.android.features.location.impl.aPermissionsState
|
||||
@@ -23,20 +24,15 @@ import io.element.android.features.location.impl.common.permissions.PermissionsE
|
||||
import io.element.android.features.location.impl.common.permissions.PermissionsState
|
||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
|
||||
import io.element.android.features.wellknown.test.aMapTilerConfig
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.dateformatter.test.FakeDateFormatter
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.location.LiveLocationShare
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.location.aLiveLocationShare
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.test
|
||||
@@ -69,9 +65,8 @@ class ShowLocationPresenterTest {
|
||||
),
|
||||
locationActions: FakeLocationActions = fakeLocationActions,
|
||||
joinedRoom: JoinedRoom = FakeJoinedRoom(),
|
||||
sessionId: SessionId = A_SESSION_ID,
|
||||
liveLocationShareManager: FakeActiveLiveLocationShareManager = FakeActiveLiveLocationShareManager(),
|
||||
remoteEnterpriseConfigProvider: FakeRemoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(),
|
||||
customMapTilerConfigProvider: CustomMapTilerConfigProvider = { Result.success(null) },
|
||||
) = ShowLocationPresenter(
|
||||
mode = mode,
|
||||
permissionsPresenterFactory = { fakePermissionsPresenter },
|
||||
@@ -80,21 +75,15 @@ class ShowLocationPresenterTest {
|
||||
dateFormatter = fakeDateFormatter,
|
||||
stringProvider = FakeStringProvider(),
|
||||
joinedRoom = joinedRoom,
|
||||
sessionId = sessionId,
|
||||
liveLocationShareManager = liveLocationShareManager,
|
||||
userLocationStateFactory = FakeUserLocationStateFactory(),
|
||||
remoteEnterpriseConfigProvider = remoteEnterpriseConfigProvider,
|
||||
customMapTilerConfigProvider = customMapTilerConfigProvider,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `present - non-null customMapStyleUrl`() = runTest {
|
||||
val mapTilerConfig = aMapTilerConfig(apiKey = "A KEY")
|
||||
val shareLocationPresenter = createShowLocationPresenter(
|
||||
sessionId = A_SESSION_ID,
|
||||
remoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(
|
||||
getResult = { WellknownRetrieverResult.Success(anElementWellKnown(mapTilerConfig = mapTilerConfig)) }
|
||||
)
|
||||
)
|
||||
val shareLocationPresenter = createShowLocationPresenter(customMapTilerConfigProvider = { Result.success(mapTilerConfig) })
|
||||
shareLocationPresenter.test {
|
||||
val state = awaitItem()
|
||||
assertThat(state.customMapTilerConfig.isLoading()).isTrue()
|
||||
@@ -131,12 +120,7 @@ class ShowLocationPresenterTest {
|
||||
fun `centers on user location`() = runTest {
|
||||
fakePermissionsPresenter.givenState(aPermissionsState(permissions = PermissionsState.Permissions.AllGranted))
|
||||
|
||||
val presenter = createShowLocationPresenter(
|
||||
sessionId = A_SESSION_ID,
|
||||
remoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(
|
||||
getResult = { WellknownRetrieverResult.Success(anElementWellKnown(mapTilerConfig = aMapTilerConfig())) }
|
||||
)
|
||||
)
|
||||
val presenter = createShowLocationPresenter(customMapTilerConfigProvider = { Result.success(aMapTilerConfig()) })
|
||||
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
|
||||
+9
-22
@@ -11,17 +11,14 @@ package io.element.android.features.login.impl.accesscontrol
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.features.enterprise.api.IsEnterpriseBuild
|
||||
import io.element.android.features.login.api.accesscontrol.AccountProviderAccessControl
|
||||
import io.element.android.features.login.impl.changeserver.AccountProviderAccessException
|
||||
import io.element.android.libraries.matrix.api.TemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultAccountProviderAccessControl(
|
||||
private val isEnterpriseBuild: IsEnterpriseBuild,
|
||||
private val enterpriseService: EnterpriseService,
|
||||
private val wellknownRetrieverFactory: WellknownRetriever.Factory,
|
||||
private val temporaryMatrixClientFactory: TemporaryMatrixClientFactory,
|
||||
) : AccountProviderAccessControl {
|
||||
override suspend fun isAllowedToConnectToAccountProvider(accountProviderUrl: String) = try {
|
||||
assertIsAllowedToConnectToAccountProvider(
|
||||
@@ -38,29 +35,19 @@ class DefaultAccountProviderAccessControl(
|
||||
title: String,
|
||||
accountProviderUrl: String,
|
||||
) {
|
||||
if (enterpriseService.isEnterpriseBuild.not()) {
|
||||
if (isEnterpriseBuild().not()) {
|
||||
// Ensure that Element Pro is not required for this account provider
|
||||
val temporaryMatrixClient = temporaryMatrixClientFactory.create(accountProviderUrl).getOrThrow()
|
||||
temporaryMatrixClient.use {
|
||||
val wellknownRetriever = wellknownRetrieverFactory.create(temporaryMatrixClient)
|
||||
val wellKnown = wellknownRetriever.getElementWellKnown(
|
||||
host = accountProviderUrl,
|
||||
// It's expected this is hardcoded to the well-known endpoint
|
||||
source = EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT,
|
||||
).dataOrNull()
|
||||
|
||||
if (wellKnown?.enforceElementPro == true) {
|
||||
throw AccountProviderAccessException.NeedElementProException(
|
||||
unauthorisedAccountProviderTitle = title,
|
||||
applicationId = ELEMENT_PRO_APPLICATION_ID,
|
||||
)
|
||||
}
|
||||
if (enterpriseService.isElementProEnforced(accountProviderUrl)) {
|
||||
throw AccountProviderAccessException.NeedElementProException(
|
||||
unauthorisedAccountProviderTitle = title,
|
||||
applicationId = ELEMENT_PRO_APPLICATION_ID,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (enterpriseService.isAllowedToConnectToHomeserver(accountProviderUrl).not()) {
|
||||
throw AccountProviderAccessException.UnauthorizedAccountProviderException(
|
||||
unauthorisedAccountProviderTitle = title,
|
||||
authorisedAccountProviderTitles = enterpriseService.defaultHomeserverList(),
|
||||
authorisedAccountProviderTitles = enterpriseService.homeserverAllowList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ class AccountProviderDataSource(
|
||||
enterpriseService: EnterpriseService,
|
||||
) {
|
||||
private val defaultAccountProvider = createAccountProvider(
|
||||
url = enterpriseService.defaultHomeserverList()
|
||||
url = enterpriseService.homeserverAllowList()
|
||||
.firstOrNull { it != EnterpriseService.ANY_ACCOUNT_PROVIDER }
|
||||
?: AuthenticationConfig.MATRIX_ORG_URL
|
||||
)
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class ChangeAccountProviderPresenter(
|
||||
@Composable
|
||||
override fun present(): ChangeAccountProviderState {
|
||||
val staticAccountProviderList = remember {
|
||||
enterpriseService.defaultHomeserverList()
|
||||
enterpriseService.homeserverAllowList()
|
||||
.filter { it != EnterpriseService.ANY_ACCOUNT_PROVIDER }
|
||||
.map { it.ensureProtocol() }
|
||||
.ifEmpty { listOf(AuthenticationConfig.MATRIX_ORG_URL) }
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ class ChooseAccountProviderPresenter(
|
||||
|
||||
val staticAccountProviderList = remember {
|
||||
// The list cannot contains ANY_ACCOUNT_PROVIDER ("*") and cannot be empty at this point
|
||||
enterpriseService.defaultHomeserverList()
|
||||
enterpriseService.homeserverAllowList()
|
||||
.map { it.ensureProtocol() }
|
||||
.map { url ->
|
||||
AccountProvider(
|
||||
|
||||
+2
-2
@@ -62,13 +62,13 @@ class OnBoardingPresenter(
|
||||
val forcedAccountProvider = remember {
|
||||
// If defaultHomeserverList() returns a singleton list, this is the default account provider.
|
||||
// In this case, the user can sign in using this homeserver, or use QrCode login
|
||||
enterpriseService.defaultHomeserverList().singleOrNull()
|
||||
enterpriseService.homeserverAllowList().singleOrNull()
|
||||
}
|
||||
val canConnectToAnyHomeserver = remember {
|
||||
enterpriseService.canConnectToAnyHomeserver()
|
||||
}
|
||||
val mustChooseAccountProvider = remember {
|
||||
!canConnectToAnyHomeserver && enterpriseService.defaultHomeserverList().size > 1
|
||||
!canConnectToAnyHomeserver && enterpriseService.homeserverAllowList().size > 1
|
||||
}
|
||||
val linkAccountProvider by produceState<String?>(initialValue = null) {
|
||||
// Account provider from the link, if allowed by the enterprise service
|
||||
|
||||
+30
-46
@@ -11,15 +11,9 @@ package io.element.android.features.login.impl.accesscontrol
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
||||
import io.element.android.features.login.impl.changeserver.AccountProviderAccessException
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetriever
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetrieverFactory
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER
|
||||
import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_2
|
||||
import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_URL
|
||||
import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Test
|
||||
@@ -30,9 +24,7 @@ class DefaultAccountProviderAccessControlTest {
|
||||
val accessControl = createDefaultAccountProviderAccessControl(
|
||||
isEnterpriseBuild = false,
|
||||
isAllowedToConnectToHomeserver = true,
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = true,
|
||||
),
|
||||
enterpriseService = FakeEnterpriseService(isElementProEnforcedResult = { true }),
|
||||
)
|
||||
accessControl.expectNeedElementProException()
|
||||
}
|
||||
@@ -43,9 +35,7 @@ class DefaultAccountProviderAccessControlTest {
|
||||
isEnterpriseBuild = false,
|
||||
// false here.
|
||||
isAllowedToConnectToHomeserver = false,
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = true,
|
||||
),
|
||||
enterpriseService = FakeEnterpriseService(isElementProEnforcedResult = { true }),
|
||||
)
|
||||
accessControl.expectNeedElementProException()
|
||||
}
|
||||
@@ -55,8 +45,9 @@ class DefaultAccountProviderAccessControlTest {
|
||||
val accessControl = createDefaultAccountProviderAccessControl(
|
||||
isEnterpriseBuild = false,
|
||||
isAllowedToConnectToHomeserver = true,
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = false,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { false }
|
||||
),
|
||||
)
|
||||
accessControl.expectAllowed()
|
||||
@@ -67,19 +58,15 @@ class DefaultAccountProviderAccessControlTest {
|
||||
val accessControl = createDefaultAccountProviderAccessControl(
|
||||
isEnterpriseBuild = false,
|
||||
isAllowedToConnectToHomeserver = true,
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = null,
|
||||
),
|
||||
)
|
||||
accessControl.expectAllowed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `foss build should allow using account provider twith missing wellknown`() = runTest {
|
||||
fun `foss build should allow using account provider with missing wellknown`() = runTest {
|
||||
val accessControl = createDefaultAccountProviderAccessControl(
|
||||
isEnterpriseBuild = false,
|
||||
isAllowedToConnectToHomeserver = true,
|
||||
elementWellKnown = null,
|
||||
)
|
||||
accessControl.expectAllowed()
|
||||
}
|
||||
@@ -90,8 +77,10 @@ class DefaultAccountProviderAccessControlTest {
|
||||
isEnterpriseBuild = false,
|
||||
isAllowedToConnectToHomeserver = false,
|
||||
allowedAccountProviders = listOf(AN_ACCOUNT_PROVIDER_2),
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = false,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { false },
|
||||
isElementProEnforcedResult = { false },
|
||||
defaultHomeserverListResult = { listOf(AN_ACCOUNT_PROVIDER_2) },
|
||||
),
|
||||
)
|
||||
accessControl.expectUnauthorizedAccountProviderException()
|
||||
@@ -102,8 +91,9 @@ class DefaultAccountProviderAccessControlTest {
|
||||
val accessControl = createDefaultAccountProviderAccessControl(
|
||||
isEnterpriseBuild = true,
|
||||
isAllowedToConnectToHomeserver = true,
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = true,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { true },
|
||||
),
|
||||
)
|
||||
accessControl.expectAllowed()
|
||||
@@ -114,8 +104,9 @@ class DefaultAccountProviderAccessControlTest {
|
||||
val accessControl = createDefaultAccountProviderAccessControl(
|
||||
isEnterpriseBuild = true,
|
||||
isAllowedToConnectToHomeserver = true,
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = false,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { false },
|
||||
),
|
||||
)
|
||||
accessControl.expectAllowed()
|
||||
@@ -127,8 +118,10 @@ class DefaultAccountProviderAccessControlTest {
|
||||
isEnterpriseBuild = true,
|
||||
isAllowedToConnectToHomeserver = false,
|
||||
allowedAccountProviders = listOf(AN_ACCOUNT_PROVIDER_2),
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = true,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { false },
|
||||
isElementProEnforcedResult = { true },
|
||||
defaultHomeserverListResult = { listOf(AN_ACCOUNT_PROVIDER_2) },
|
||||
),
|
||||
)
|
||||
accessControl.expectUnauthorizedAccountProviderException()
|
||||
@@ -140,8 +133,10 @@ class DefaultAccountProviderAccessControlTest {
|
||||
isEnterpriseBuild = true,
|
||||
isAllowedToConnectToHomeserver = false,
|
||||
allowedAccountProviders = listOf(AN_ACCOUNT_PROVIDER_2),
|
||||
elementWellKnown = anElementWellKnown(
|
||||
enforceElementPro = false,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { false },
|
||||
isElementProEnforcedResult = { false },
|
||||
defaultHomeserverListResult = { listOf(AN_ACCOUNT_PROVIDER_2) },
|
||||
),
|
||||
)
|
||||
accessControl.expectUnauthorizedAccountProviderException()
|
||||
@@ -151,25 +146,14 @@ class DefaultAccountProviderAccessControlTest {
|
||||
isEnterpriseBuild: Boolean = false,
|
||||
isAllowedToConnectToHomeserver: Boolean = false,
|
||||
allowedAccountProviders: List<String> = emptyList(),
|
||||
elementWellKnown: ElementWellKnown? = null,
|
||||
) = DefaultAccountProviderAccessControl(
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isEnterpriseBuild = isEnterpriseBuild,
|
||||
enterpriseService: FakeEnterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { isAllowedToConnectToHomeserver },
|
||||
defaultHomeserverListResult = { allowedAccountProviders },
|
||||
),
|
||||
wellknownRetrieverFactory = FakeWellknownRetrieverFactory(
|
||||
wellknownRetriever = FakeWellknownRetriever(
|
||||
getElementWellKnownResult = { _, _ ->
|
||||
if (elementWellKnown == null) {
|
||||
WellknownRetrieverResult.NotFound
|
||||
} else {
|
||||
WellknownRetrieverResult.Success(elementWellKnown)
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(),
|
||||
isElementProEnforcedResult = { false },
|
||||
)
|
||||
) = DefaultAccountProviderAccessControl(
|
||||
isEnterpriseBuild = { isEnterpriseBuild },
|
||||
enterpriseService = enterpriseService,
|
||||
)
|
||||
|
||||
private fun DefaultAccountProviderAccessControl.expectNeedElementProException() {
|
||||
|
||||
+15
-23
@@ -16,22 +16,15 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider
|
||||
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
|
||||
import io.element.android.features.login.impl.error.ChangeServerError
|
||||
import io.element.android.features.login.impl.localnetwork.LocalNetworkPermissionGate
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetriever
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetrieverFactory
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||
import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.test.auth.aMatrixHomeServerDetails
|
||||
import io.element.android.libraries.permissions.api.localnetwork.LocalNetworkPermissionDialog
|
||||
import io.element.android.libraries.permissions.test.FakeLocalNetworkPermissionAdvisor
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenter
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenterFactory
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
@@ -64,6 +57,7 @@ class ChangeServerPresenterTest {
|
||||
authenticationService = authenticationService,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { false },
|
||||
),
|
||||
).test {
|
||||
val initialState = awaitItem()
|
||||
@@ -86,6 +80,7 @@ class ChangeServerPresenterTest {
|
||||
createPresenter(
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { false },
|
||||
),
|
||||
authenticationService = authenticationService,
|
||||
).test {
|
||||
@@ -113,6 +108,7 @@ class ChangeServerPresenterTest {
|
||||
createPresenter(
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { false },
|
||||
),
|
||||
authenticationService = authenticationService,
|
||||
).test {
|
||||
@@ -136,6 +132,7 @@ class ChangeServerPresenterTest {
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = isAllowedToConnectToHomeserverResult,
|
||||
defaultHomeserverListResult = { listOf("element.io") },
|
||||
isElementProEnforcedResult = { false },
|
||||
),
|
||||
).test {
|
||||
val initialState = awaitItem()
|
||||
@@ -159,23 +156,19 @@ class ChangeServerPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - change server element pro required error`() = runTest {
|
||||
val getElementWellKnownResult = lambdaRecorder { homeserver: String, _: EnterpriseRemoteConfigSource ->
|
||||
assertThat(homeserver).isEqualTo(A_HOMESERVER_URL)
|
||||
WellknownRetrieverResult.Success(
|
||||
anElementWellKnown(
|
||||
enforceElementPro = true,
|
||||
)
|
||||
)
|
||||
}
|
||||
val isEnterpriseBuildLambda = lambdaRecorder<Boolean> { false }
|
||||
createPresenter(
|
||||
wellknownRetriever = FakeWellknownRetriever(
|
||||
getElementWellKnownResult = getElementWellKnownResult,
|
||||
),
|
||||
isEnterpriseBuild = isEnterpriseBuildLambda,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isElementProEnforcedResult = { true },
|
||||
)
|
||||
).test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
|
||||
val anAccountProvider = AccountProvider(url = A_HOMESERVER_URL)
|
||||
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(anAccountProvider))
|
||||
// Skip loading state
|
||||
skipItems(1)
|
||||
val failureState = awaitItem()
|
||||
assertThat(
|
||||
(failureState.changeServerAction.errorOrNull() as ChangeServerError.NeedElementPro).unauthorisedAccountProviderTitle
|
||||
@@ -183,7 +176,7 @@ class ChangeServerPresenterTest {
|
||||
assertThat(
|
||||
(failureState.changeServerAction.errorOrNull() as ChangeServerError.NeedElementPro).applicationId
|
||||
).isEqualTo("io.element.enterprise")
|
||||
getElementWellKnownResult.assertions().isCalledOnce()
|
||||
isEnterpriseBuildLambda.assertions().isCalledOnce()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +230,7 @@ class ChangeServerPresenterTest {
|
||||
val permissionsPresenter = FakePermissionsPresenter()
|
||||
createPresenter(
|
||||
authenticationService = authenticationService,
|
||||
enterpriseService = FakeEnterpriseService(isAllowedToConnectToHomeserverResult = { true }),
|
||||
enterpriseService = FakeEnterpriseService(isAllowedToConnectToHomeserverResult = { true }, isElementProEnforcedResult = { false }),
|
||||
localNetworkPermissionAdvisor = FakeLocalNetworkPermissionAdvisor(shouldPrompt = true),
|
||||
permissionsPresenter = permissionsPresenter,
|
||||
).test {
|
||||
@@ -259,16 +252,15 @@ class ChangeServerPresenterTest {
|
||||
authenticationService: FakeMatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
||||
accountProviderDataSource: AccountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()),
|
||||
enterpriseService: EnterpriseService = FakeEnterpriseService(),
|
||||
wellknownRetriever: WellknownRetriever = FakeWellknownRetriever(),
|
||||
localNetworkPermissionAdvisor: FakeLocalNetworkPermissionAdvisor = FakeLocalNetworkPermissionAdvisor(),
|
||||
permissionsPresenter: FakePermissionsPresenter = FakePermissionsPresenter(),
|
||||
isEnterpriseBuild: () -> Boolean = { false },
|
||||
) = ChangeServerPresenter(
|
||||
authenticationService = authenticationService,
|
||||
accountProviderDataSource = accountProviderDataSource,
|
||||
defaultAccountProviderAccessControl = DefaultAccountProviderAccessControl(
|
||||
enterpriseService = enterpriseService,
|
||||
wellknownRetrieverFactory = FakeWellknownRetrieverFactory(wellknownRetriever = wellknownRetriever),
|
||||
temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(),
|
||||
isEnterpriseBuild = isEnterpriseBuild,
|
||||
),
|
||||
localNetworkPermissionGate = LocalNetworkPermissionGate(
|
||||
advisor = localNetworkPermissionAdvisor,
|
||||
|
||||
+5
-7
@@ -12,13 +12,12 @@ import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.appconfig.AuthenticationConfig
|
||||
import io.element.android.appconfig.OnBoardingConfig
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.features.enterprise.api.IsEnterpriseBuild
|
||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
||||
import io.element.android.features.login.impl.accesscontrol.DefaultAccountProviderAccessControl
|
||||
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
|
||||
import io.element.android.features.login.impl.localnetwork.LocalNetworkPermissionGate
|
||||
import io.element.android.features.login.impl.login.LoginModePresenter
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetriever
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetrieverFactory
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
@@ -29,7 +28,6 @@ import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL_2
|
||||
import io.element.android.libraries.matrix.test.A_LOGIN_HINT
|
||||
import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||
@@ -41,7 +39,6 @@ import io.element.android.libraries.permissions.test.FakePermissionsPresenterFac
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
||||
import io.element.android.libraries.sessionstorage.test.aSessionData
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.test
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -186,6 +183,7 @@ class OnBoardingPresenterTest {
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG, EnterpriseService.ANY_ACCOUNT_PROVIDER) },
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { false },
|
||||
),
|
||||
)
|
||||
presenter.test {
|
||||
@@ -259,6 +257,7 @@ class OnBoardingPresenterTest {
|
||||
),
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isAllowedToConnectToHomeserverResult = { true },
|
||||
isElementProEnforcedResult = { false },
|
||||
),
|
||||
loginModePresenter = createLoginModePresenter(
|
||||
authenticationService = authenticationService,
|
||||
@@ -295,7 +294,7 @@ private fun createPresenter(
|
||||
),
|
||||
buildMeta: BuildMeta = aBuildMeta(),
|
||||
enterpriseService: EnterpriseService = FakeEnterpriseService(),
|
||||
wellknownRetriever: WellknownRetriever = FakeWellknownRetriever(),
|
||||
isEnterpriseBuild: IsEnterpriseBuild = { false },
|
||||
rageshakeFeatureAvailability: () -> Flow<Boolean> = { flowOf(true) },
|
||||
loginModePresenter: LoginModePresenter = createLoginModePresenter(),
|
||||
onBoardingLogoResIdProvider: OnBoardingLogoResIdProvider = OnBoardingLogoResIdProvider { null },
|
||||
@@ -307,8 +306,7 @@ private fun createPresenter(
|
||||
enterpriseService = enterpriseService,
|
||||
defaultAccountProviderAccessControl = DefaultAccountProviderAccessControl(
|
||||
enterpriseService = enterpriseService,
|
||||
wellknownRetrieverFactory = FakeWellknownRetrieverFactory(wellknownRetriever = wellknownRetriever),
|
||||
temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(),
|
||||
isEnterpriseBuild = isEnterpriseBuild,
|
||||
),
|
||||
rageshakeFeatureAvailability = rageshakeFeatureAvailability,
|
||||
loginModePresenter = loginModePresenter,
|
||||
|
||||
+3
-1
@@ -30,6 +30,7 @@ import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.core.data.ByteUnit
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.matrix.api.analytics.GetDatabaseSizesUseCase
|
||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
@@ -50,6 +51,7 @@ class DeveloperSettingsPresenter(
|
||||
private val databaseSizesUseCase: GetDatabaseSizesUseCase,
|
||||
private val fileSizeFormatter: FileSizeFormatter,
|
||||
private val markAllRoomsAsRead: MarkAllRoomsAsRead,
|
||||
private val buildMeta: BuildMeta,
|
||||
) : Presenter<DeveloperSettingsState> {
|
||||
@Composable
|
||||
override fun present(): DeveloperSettingsState {
|
||||
@@ -117,7 +119,7 @@ class DeveloperSettingsPresenter(
|
||||
databaseSizes = databaseSizes.value,
|
||||
clearCacheAction = clearCacheAction.value,
|
||||
markAllRoomsAsReadAction = markAllRoomsAsReadAction.value,
|
||||
isEnterpriseBuild = enterpriseService.isEnterpriseBuild,
|
||||
isEnterpriseBuild = buildMeta.isEnterpriseBuild,
|
||||
showColorPicker = showColorPicker,
|
||||
deviceId = deviceId,
|
||||
eventSink = ::handleEvent,
|
||||
|
||||
+6
-4
@@ -23,12 +23,14 @@ import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.core.data.megaBytes
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.matrix.api.analytics.GetDatabaseSizesUseCase
|
||||
import io.element.android.libraries.matrix.api.analytics.SdkStoreSizes
|
||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.test.A_DEVICE_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
@@ -108,10 +110,8 @@ class DeveloperSettingsPresenterTest {
|
||||
fun `present - enterprise build can change the brand color`() = runTest {
|
||||
val overrideBrandColorResult = lambdaRecorder<SessionId?, String?, Unit> { _, _ -> }
|
||||
val presenter = createDeveloperSettingsPresenter(
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
isEnterpriseBuild = true,
|
||||
overrideBrandColorResult = overrideBrandColorResult,
|
||||
)
|
||||
enterpriseService = FakeEnterpriseService(overrideBrandColorResult = overrideBrandColorResult),
|
||||
buildMeta = aBuildMeta(isEnterpriseBuild = true),
|
||||
)
|
||||
presenter.test {
|
||||
skipItems(1)
|
||||
@@ -179,6 +179,7 @@ class DeveloperSettingsPresenterTest {
|
||||
vacuumStoresUseCase: VacuumStoresUseCase = VacuumStoresUseCase {},
|
||||
databaseSizesUseCase: GetDatabaseSizesUseCase = GetDatabaseSizesUseCase { Result.success(SdkStoreSizes(null, null, null, null)) },
|
||||
markAllRoomsAsRead: FakeMarkAllRoomsAsRead = FakeMarkAllRoomsAsRead(),
|
||||
buildMeta: BuildMeta = aBuildMeta(),
|
||||
): DeveloperSettingsPresenter {
|
||||
return DeveloperSettingsPresenter(
|
||||
appDeveloperSettingsPresenter = { anAppDeveloperSettingsState() },
|
||||
@@ -191,6 +192,7 @@ class DeveloperSettingsPresenterTest {
|
||||
databaseSizesUseCase = databaseSizesUseCase,
|
||||
fileSizeFormatter = FakeFileSizeFormatter(),
|
||||
markAllRoomsAsRead = markAllRoomsAsRead,
|
||||
buildMeta = buildMeta,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user