First Commit

This commit is contained in:
2025-12-18 16:28:50 +07:00
commit 8c3e4f491f
9974 changed files with 396488 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
}
android {
namespace = "io.element.android.features.enterprise.api"
}
dependencies {
implementation(projects.libraries.compound)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector 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
sealed interface BugReportUrl {
data object UseDefault : BugReportUrl
data object Disabled : BugReportUrl
data class Custom(
val url: String,
) : BugReportUrl
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector 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
import androidx.compose.ui.graphics.Color
import io.element.android.compound.colors.SemanticColorsLightDark
import io.element.android.libraries.matrix.api.core.SessionId
import kotlinx.coroutines.flow.Flow
interface EnterpriseService {
val isEnterpriseBuild: Boolean
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
fun defaultHomeserverList(): List<String>
suspend fun isAllowedToConnectToHomeserver(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.
* @param brandColor the color in hex format (#RRGGBBAA or #RRGGBB), or null to reset to default.
*/
suspend fun overrideBrandColor(sessionId: SessionId?, brandColor: String?)
fun brandColorsFlow(sessionId: SessionId?): Flow<Color?>
fun semanticColorsFlow(sessionId: SessionId?): Flow<SemanticColorsLightDark>
fun firebasePushGateway(): String?
fun unifiedPushDefaultPushGateway(): String?
fun bugReportUrlFlow(sessionId: SessionId?): Flow<BugReportUrl>
companion object {
const val ANY_ACCOUNT_PROVIDER = "*"
}
}
fun EnterpriseService.canConnectToAnyHomeserver(): Boolean {
return defaultHomeserverList().let {
it.isEmpty() || it.contains(EnterpriseService.ANY_ACCOUNT_PROVIDER)
}
}
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector 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
interface SessionEnterpriseService {
suspend fun isElementCallAvailable(): Boolean
suspend fun init()
}
@@ -0,0 +1,29 @@
import extension.setupDependencyInjection
import extension.testCommonDependencies
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
}
android {
namespace = "io.element.android.features.enterprise.impl"
}
setupDependencyInjection()
dependencies {
implementation(projects.libraries.compound)
api(projects.features.enterprise.api)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector 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 androidx.compose.ui.graphics.Color
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.compound.colors.SemanticColorsLightDark
import io.element.android.features.enterprise.api.BugReportUrl
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.matrix.api.core.SessionId
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 fun defaultHomeserverList(): List<String> = emptyList()
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true
override suspend fun overrideBrandColor(sessionId: SessionId?, brandColor: String?) = Unit
override fun brandColorsFlow(sessionId: SessionId?): Flow<Color?> {
return flowOf(null)
}
override fun semanticColorsFlow(sessionId: SessionId?): Flow<SemanticColorsLightDark> {
return flowOf(SemanticColorsLightDark.default)
}
override fun firebasePushGateway(): String? = null
override fun unifiedPushDefaultPushGateway(): String? = null
override fun bugReportUrlFlow(sessionId: SessionId?): Flow<BugReportUrl> {
return flowOf(BugReportUrl.UseDefault)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector 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.ContributesBinding
import io.element.android.features.enterprise.api.SessionEnterpriseService
import io.element.android.libraries.di.SessionScope
@ContributesBinding(SessionScope::class)
class DefaultSessionEnterpriseService : SessionEnterpriseService {
override suspend fun init() = Unit
override suspend fun isElementCallAvailable(): Boolean = true
}
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector 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 app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.compound.colors.SemanticColorsLightDark
import io.element.android.features.enterprise.api.BugReportUrl
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
import io.element.android.libraries.matrix.test.A_SESSION_ID
import kotlinx.coroutines.test.runTest
import org.junit.Test
class DefaultEnterpriseServiceTest {
@Test
fun `isEnterpriseBuild is false`() {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.isEnterpriseBuild).isFalse()
}
@Test
fun `defaultHomeserverList should return empty list`() {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.defaultHomeserverList()).isEmpty()
}
@Test
fun `isAllowedToConnectToHomeserver is true for all homeserver urls`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.isAllowedToConnectToHomeserver(A_HOMESERVER_URL)).isTrue()
}
@Test
fun `isEnterpriseUser always return false`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.isEnterpriseUser(A_SESSION_ID)).isFalse()
}
@Test
fun `semanticColorsFlow always emits the same value`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
defaultEnterpriseService.semanticColorsFlow(null).test {
val initialState = awaitItem()
assertThat(initialState).isEqualTo(SemanticColorsLightDark.default)
awaitComplete()
}
}
@Test
fun `brandColorsFlow always emits null`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
defaultEnterpriseService.brandColorsFlow(null).test {
val initialState = awaitItem()
assertThat(initialState).isNull()
awaitComplete()
}
}
@Test
fun `semanticColorsFlow always emits the same value for a session`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
defaultEnterpriseService.semanticColorsFlow(A_SESSION_ID).test {
val initialState = awaitItem()
assertThat(initialState).isEqualTo(SemanticColorsLightDark.default)
awaitComplete()
}
}
@Test
fun `overrideBrandColor has no effect`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
defaultEnterpriseService.overrideBrandColor(A_SESSION_ID, "aColor")
}
@Test
fun `firebasePushGateway returns null`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.firebasePushGateway()).isNull()
}
@Test
fun `unifiedPushDefaultPushGateway returns null`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
assertThat(defaultEnterpriseService.unifiedPushDefaultPushGateway()).isNull()
}
@Test
fun `bugReportUrlFlow only emits UseDefault`() = runTest {
val defaultEnterpriseService = DefaultEnterpriseService()
defaultEnterpriseService.bugReportUrlFlow(A_SESSION_ID).test {
assertThat(awaitItem()).isEqualTo(BugReportUrl.UseDefault)
awaitComplete()
}
}
}
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector 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 com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
class DefaultSessionEnterpriseServiceTest {
@Test
fun `isElementCallAvailable is always true`() = runTest {
val service = DefaultSessionEnterpriseService()
assertThat(service.isElementCallAvailable()).isTrue()
}
}
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.features.enterprise.test"
}
dependencies {
api(projects.features.enterprise.api)
implementation(projects.libraries.compound)
implementation(projects.libraries.matrix.api)
implementation(projects.tests.testutils)
}
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector 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
import androidx.compose.ui.graphics.Color
import io.element.android.compound.colors.SemanticColorsLightDark
import io.element.android.features.enterprise.api.BugReportUrl
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.flow.Flow
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() },
initialSemanticColors: SemanticColorsLightDark = SemanticColorsLightDark.default,
initialBrandColor: Color? = null,
private val overrideBrandColorResult: (SessionId?, String?) -> Unit = { _, _ -> lambdaError() },
private val firebasePushGatewayResult: () -> String? = { lambdaError() },
private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() },
) : EnterpriseService {
private val brandColorState = MutableStateFlow(initialBrandColor)
private val semanticColorsState = MutableStateFlow(initialSemanticColors)
override suspend fun isEnterpriseUser(sessionId: SessionId): Boolean = simulateLongTask {
isEnterpriseUserResult(sessionId)
}
override fun defaultHomeserverList(): List<String> {
return defaultHomeserverListResult()
}
override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean = simulateLongTask {
isAllowedToConnectToHomeserverResult(homeserverUrl)
}
override suspend fun overrideBrandColor(sessionId: SessionId?, brandColor: String?) = simulateLongTask {
overrideBrandColorResult(sessionId, brandColor)
}
override fun brandColorsFlow(sessionId: SessionId?): Flow<Color?> {
return brandColorState.asStateFlow()
}
override fun semanticColorsFlow(sessionId: SessionId?): Flow<SemanticColorsLightDark> {
return semanticColorsState.asStateFlow()
}
override fun firebasePushGateway(): String? {
return firebasePushGatewayResult()
}
override fun unifiedPushDefaultPushGateway(): String? {
return unifiedPushDefaultPushGatewayResult()
}
val bugReportUrlMutableFlow = MutableStateFlow<BugReportUrl>(BugReportUrl.UseDefault)
override fun bugReportUrlFlow(sessionId: SessionId?): Flow<BugReportUrl> {
return bugReportUrlMutableFlow.asStateFlow()
}
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector 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
import io.element.android.features.enterprise.api.SessionEnterpriseService
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask
class FakeSessionEnterpriseService(
private val isElementCallAvailableResult: () -> Boolean = { lambdaError() },
) : SessionEnterpriseService {
override suspend fun init() {
}
override suspend fun isElementCallAvailable(): Boolean = simulateLongTask {
isElementCallAvailableResult()
}
}