Skip to content

Commit b35feb0

Browse files
authored
Merge pull request #4285 from element-hq/feature/bma/appConfig
Prepare application for being configurable
2 parents a3732fe + 03e05ff commit b35feb0

File tree

21 files changed

+303
-171
lines changed

21 files changed

+303
-171
lines changed

app/build.gradle.kts

+3-10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.android.build.api.variant.FilterConfiguration.FilterType.ABI
1111
import com.android.build.gradle.internal.tasks.factory.dependsOn
1212
import com.android.build.gradle.tasks.GenerateBuildConfig
13+
import config.BuildTimeConfig
1314
import extension.AssetCopyTask
1415
import extension.ComponentMergingStrategy
1516
import extension.GitBranchNameValueSource
@@ -43,11 +44,7 @@ android {
4344
namespace = "io.element.android.x"
4445

4546
defaultConfig {
46-
applicationId = if (isEnterpriseBuild) {
47-
"io.element.enterprise"
48-
} else {
49-
"io.element.android.x"
50-
}
47+
applicationId = BuildTimeConfig.APPLICATION_ID
5148
targetSdk = Versions.TARGET_SDK
5249
versionCode = Versions.VERSION_CODE
5350
versionName = Versions.VERSION_NAME
@@ -97,11 +94,7 @@ android {
9794
}
9895
}
9996

100-
val baseAppName = if (isEnterpriseBuild) {
101-
"Element Enterprise"
102-
} else {
103-
"Element X"
104-
}
97+
val baseAppName = BuildTimeConfig.APPLICATION_NAME
10598
logger.warnInBox("Building $baseAppName")
10699

107100
buildTypes {

app/src/main/kotlin/io/element/android/x/di/AppModule.kt

+20-17
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,26 @@ object AppModule {
7373
@ApplicationContext context: Context,
7474
buildType: BuildType,
7575
enterpriseService: EnterpriseService,
76-
) = BuildMeta(
77-
isDebuggable = BuildConfig.DEBUG,
78-
buildType = buildType,
79-
applicationName = ApplicationConfig.APPLICATION_NAME.takeIf { it.isNotEmpty() } ?: context.getString(R.string.app_name),
80-
productionApplicationName = ApplicationConfig.PRODUCTION_APPLICATION_NAME,
81-
desktopApplicationName = ApplicationConfig.DESKTOP_APPLICATION_NAME,
82-
applicationId = BuildConfig.APPLICATION_ID,
83-
isEnterpriseBuild = enterpriseService.isEnterpriseBuild,
84-
// TODO EAx Config.LOW_PRIVACY_LOG_ENABLE,
85-
lowPrivacyLoggingEnabled = false,
86-
versionName = BuildConfig.VERSION_NAME,
87-
versionCode = context.getVersionCodeFromManifest(),
88-
gitRevision = BuildConfig.GIT_REVISION,
89-
gitBranchName = BuildConfig.GIT_BRANCH_NAME,
90-
flavorDescription = BuildConfig.FLAVOR_DESCRIPTION,
91-
flavorShortDescription = BuildConfig.SHORT_FLAVOR_DESCRIPTION,
92-
)
76+
): BuildMeta {
77+
val applicationName = ApplicationConfig.APPLICATION_NAME.takeIf { it.isNotEmpty() } ?: context.getString(R.string.app_name)
78+
return BuildMeta(
79+
isDebuggable = BuildConfig.DEBUG,
80+
buildType = buildType,
81+
applicationName = applicationName,
82+
productionApplicationName = if (enterpriseService.isEnterpriseBuild) applicationName else ApplicationConfig.PRODUCTION_APPLICATION_NAME,
83+
desktopApplicationName = if (enterpriseService.isEnterpriseBuild) applicationName else ApplicationConfig.DESKTOP_APPLICATION_NAME,
84+
applicationId = BuildConfig.APPLICATION_ID,
85+
isEnterpriseBuild = enterpriseService.isEnterpriseBuild,
86+
// TODO EAx Config.LOW_PRIVACY_LOG_ENABLE,
87+
lowPrivacyLoggingEnabled = false,
88+
versionName = BuildConfig.VERSION_NAME,
89+
versionCode = context.getVersionCodeFromManifest(),
90+
gitRevision = BuildConfig.GIT_REVISION,
91+
gitBranchName = BuildConfig.GIT_BRANCH_NAME,
92+
flavorDescription = BuildConfig.FLAVOR_DESCRIPTION,
93+
flavorShortDescription = BuildConfig.SHORT_FLAVOR_DESCRIPTION,
94+
)
95+
}
9396

9497
@Provides
9598
@SingleIn(AppScope::class)

appconfig/src/main/kotlin/io/element/android/appconfig/AuthenticationConfig.kt

-5
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ package io.element.android.appconfig
1010
object AuthenticationConfig {
1111
const val MATRIX_ORG_URL = "https://matrix.org"
1212

13-
/**
14-
* Default homeserver url to sign in with, unless the user selects a different one.
15-
*/
16-
const val DEFAULT_HOMESERVER_URL = MATRIX_ORG_URL
17-
1813
/**
1914
* URL with some docs that explain what's sliding sync and how to add it to your home server.
2015
*/

enterprise

features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
1313
interface EnterpriseService {
1414
val isEnterpriseBuild: Boolean
1515
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
16+
fun defaultHomeserver(): String?
1617

1718
fun semanticColorsLight(): SemanticColors
1819
fun semanticColorsDark(): SemanticColors

features/enterprise/impl/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class DefaultEnterpriseService @Inject constructor() : EnterpriseService {
2222

2323
override suspend fun isEnterpriseUser(sessionId: SessionId) = false
2424

25+
override fun defaultHomeserver() = null
26+
2527
override fun semanticColorsLight(): SemanticColors = compoundColorsLight
2628

2729
override fun semanticColorsDark(): SemanticColors = compoundColorsDark

features/enterprise/impl/src/test/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseServiceTest.kt

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ class DefaultEnterpriseServiceTest {
1919
assertThat(defaultEnterpriseService.isEnterpriseBuild).isFalse()
2020
}
2121

22+
@Test
23+
fun `defaultHomeserver should return null`() {
24+
val defaultEnterpriseService = DefaultEnterpriseService()
25+
assertThat<String?>(defaultEnterpriseService.defaultHomeserver()).isNull()
26+
}
27+
2228
@Test
2329
fun `isEnterpriseUser always return false`() = runTest {
2430
val defaultEnterpriseService = DefaultEnterpriseService()
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2025 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
plugins {
8+
id("io.element.android-library")
9+
}
10+
11+
android {
12+
namespace = "io.element.android.features.enterprise.test"
13+
}
14+
15+
dependencies {
16+
api(projects.features.enterprise.api)
17+
implementation(libs.compound)
18+
implementation(projects.libraries.matrix.api)
19+
implementation(projects.tests.testutils)
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2025 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.enterprise.test
9+
10+
import io.element.android.compound.tokens.generated.SemanticColors
11+
import io.element.android.features.enterprise.api.EnterpriseService
12+
import io.element.android.libraries.matrix.api.core.SessionId
13+
import io.element.android.tests.testutils.lambda.lambdaError
14+
import io.element.android.tests.testutils.simulateLongTask
15+
16+
class FakeEnterpriseService(
17+
override val isEnterpriseBuild: Boolean = false,
18+
private val isEnterpriseUserResult: (SessionId) -> Boolean = { lambdaError() },
19+
private val defaultHomeserverResult: () -> String? = { A_FAKE_HOMESERVER },
20+
private val semanticColorsLightResult: () -> SemanticColors = { lambdaError() },
21+
private val semanticColorsDarkResult: () -> SemanticColors = { lambdaError() },
22+
) : EnterpriseService {
23+
override suspend fun isEnterpriseUser(sessionId: SessionId): Boolean = simulateLongTask {
24+
isEnterpriseUserResult(sessionId)
25+
}
26+
27+
override fun defaultHomeserver(): String? {
28+
return defaultHomeserverResult()
29+
}
30+
31+
override fun semanticColorsLight(): SemanticColors {
32+
return semanticColorsLightResult()
33+
}
34+
35+
override fun semanticColorsDark(): SemanticColors {
36+
return semanticColorsDarkResult()
37+
}
38+
39+
companion object {
40+
const val A_FAKE_HOMESERVER = "a_fake_homeserver"
41+
}
42+
}

features/login/impl/build.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP)
2828

2929
dependencies {
3030
implementation(projects.appconfig)
31+
implementation(projects.features.enterprise.api)
3132
implementation(projects.libraries.core)
3233
implementation(projects.libraries.androidutils)
3334
implementation(projects.libraries.architecture)
@@ -55,6 +56,7 @@ dependencies {
5556
testImplementation(libs.test.robolectric)
5657
testImplementation(libs.test.truth)
5758
testImplementation(libs.test.turbine)
59+
testImplementation(projects.features.enterprise.test)
5860
testImplementation(projects.libraries.matrix.test)
5961
testImplementation(projects.libraries.oidc.impl)
6062
testImplementation(projects.libraries.permissions.test)

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSource.kt

+14-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
package io.element.android.features.login.impl.accountprovider
99

10-
import io.element.android.features.login.impl.util.defaultAccountProvider
10+
import io.element.android.appconfig.AuthenticationConfig
11+
import io.element.android.features.enterprise.api.EnterpriseService
1112
import io.element.android.libraries.di.AppScope
1213
import io.element.android.libraries.di.SingleIn
1314
import kotlinx.coroutines.flow.MutableStateFlow
@@ -16,7 +17,18 @@ import kotlinx.coroutines.flow.asStateFlow
1617
import javax.inject.Inject
1718

1819
@SingleIn(AppScope::class)
19-
class AccountProviderDataSource @Inject constructor() {
20+
class AccountProviderDataSource @Inject constructor(
21+
enterpriseService: EnterpriseService,
22+
) {
23+
private val defaultAccountProvider = (enterpriseService.defaultHomeserver() ?: AuthenticationConfig.MATRIX_ORG_URL).let { url ->
24+
AccountProvider(
25+
url = url,
26+
subtitle = null,
27+
isPublic = url == AuthenticationConfig.MATRIX_ORG_URL,
28+
isMatrixOrg = url == AuthenticationConfig.MATRIX_ORG_URL,
29+
)
30+
}
31+
2032
private val accountProvider: MutableStateFlow<AccountProvider> = MutableStateFlow(
2133
defaultAccountProvider
2234
)

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/util/LoginConstants.kt

-18
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2025 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.login.impl.accountprovider
9+
10+
import app.cash.turbine.test
11+
import com.google.common.truth.Truth.assertThat
12+
import io.element.android.appconfig.AuthenticationConfig
13+
import io.element.android.features.enterprise.test.FakeEnterpriseService
14+
import io.element.android.tests.testutils.WarmUpRule
15+
import kotlinx.coroutines.test.runTest
16+
import org.junit.Rule
17+
import org.junit.Test
18+
19+
class AccountProviderDataSourceTest {
20+
@get:Rule
21+
val warmUpRule = WarmUpRule()
22+
23+
@Test
24+
fun `present - initial state`() = runTest {
25+
val sut = AccountProviderDataSource(FakeEnterpriseService())
26+
sut.flow().test {
27+
val initialState = awaitItem()
28+
assertThat(initialState).isEqualTo(
29+
AccountProvider(
30+
url = FakeEnterpriseService.A_FAKE_HOMESERVER,
31+
title = FakeEnterpriseService.A_FAKE_HOMESERVER,
32+
subtitle = null,
33+
isPublic = false,
34+
isMatrixOrg = false,
35+
isValid = false,
36+
)
37+
)
38+
}
39+
}
40+
41+
@Test
42+
fun `present - initial state - matrix org`() = runTest {
43+
val sut = AccountProviderDataSource(FakeEnterpriseService(
44+
defaultHomeserverResult = { AuthenticationConfig.MATRIX_ORG_URL }
45+
))
46+
sut.flow().test {
47+
val initialState = awaitItem()
48+
assertThat(initialState).isEqualTo(
49+
AccountProvider(
50+
url = AuthenticationConfig.MATRIX_ORG_URL,
51+
title = "matrix.org",
52+
subtitle = null,
53+
isPublic = true,
54+
isMatrixOrg = true,
55+
isValid = false,
56+
)
57+
)
58+
}
59+
}
60+
61+
@Test
62+
fun `present - user change and reset`() = runTest {
63+
val sut = AccountProviderDataSource(FakeEnterpriseService())
64+
sut.flow().test {
65+
val initialState = awaitItem()
66+
assertThat(initialState.url).isEqualTo(FakeEnterpriseService.A_FAKE_HOMESERVER)
67+
sut.userSelection(AccountProvider(url = "https://example.com"))
68+
val changedState = awaitItem()
69+
assertThat(changedState).isEqualTo(
70+
AccountProvider(
71+
url = "https://example.com",
72+
title = "example.com",
73+
subtitle = null,
74+
isPublic = false,
75+
isMatrixOrg = false,
76+
isValid = false,
77+
)
78+
)
79+
sut.reset()
80+
val resetState = awaitItem()
81+
assertThat(resetState.url).isEqualTo(FakeEnterpriseService.A_FAKE_HOMESERVER)
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)