Allow adding extra elements to the developer settings from external modules (#7230)

* Add `ExtraDeveloperOptionsRenderer` to display extra UI components in the developer settings screen. It defaults to not displaying anything, using `NoopExtraDeveloperOptionsRenderer`

* Add `EnterpriseService.overriddenElementWellKnown` method to fetch the current overridden element well known value, if any

* Modify the well known retrievers to use the overridden value if it's there. Also extract the JSON parsing to its own `ElementWellKnownParser` component.

* Bump enterprise repo reference.
This commit is contained in:
Jorge Martin Espinosa
2026-07-21 10:18:56 +02:00
committed by GitHub
parent 10161a686f
commit 925376b6af
24 changed files with 192 additions and 13 deletions
+1
View File
@@ -17,4 +17,5 @@ dependencies {
implementation(projects.libraries.compound)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.wellknown.api)
}
@@ -11,6 +11,7 @@ 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 io.element.android.libraries.wellknown.api.ElementWellKnown
import kotlinx.coroutines.flow.Flow
interface EnterpriseService {
@@ -41,6 +42,11 @@ 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?
companion object {
const val ANY_ACCOUNT_PROVIDER = "*"
}
@@ -23,6 +23,7 @@ dependencies {
api(projects.features.enterprise.api)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.wellknown.api)
testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
@@ -15,6 +15,7 @@ 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.libraries.wellknown.api.ElementWellKnown
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
@@ -45,4 +46,6 @@ class DefaultEnterpriseService : EnterpriseService {
}
override fun getNoisyNotificationChannelId(sessionId: SessionId): String? = null
override fun overriddenElementWellKnown(): ElementWellKnown? = null
}
@@ -18,5 +18,6 @@ dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.compound)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.wellknown.api)
implementation(projects.tests.testutils)
}
@@ -13,6 +13,7 @@ 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.libraries.wellknown.api.ElementWellKnown
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.flow.Flow
@@ -31,6 +32,7 @@ class FakeEnterpriseService(
private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() },
private val getNoisyNotificationChannelIdResult: (SessionId?) -> String? = { lambdaError() },
private val tweakMasUrlResult: (String, String) -> String = { _, _ -> lambdaError() },
private val overrideWellKnownResult: () -> ElementWellKnown? = { lambdaError() },
) : EnterpriseService {
private val brandColorState = MutableStateFlow(initialBrandColor)
private val semanticColorsState = MutableStateFlow(initialSemanticColors)
@@ -79,4 +81,8 @@ class FakeEnterpriseService(
override fun getNoisyNotificationChannelId(sessionId: SessionId): String? {
return getNoisyNotificationChannelIdResult(sessionId)
}
override fun overriddenElementWellKnown(): ElementWellKnown? {
return overrideWellKnownResult()
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-library")
id("io.element.android-compose-library")
id("kotlin-parcelize")
}
@@ -0,0 +1,19 @@
/*
* 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.preferences.api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
/**
* Component for rendering extra developer options in the preferences screen.
*/
interface ExtraDeveloperOptionsRenderer {
@Composable
fun Render(modifier: Modifier)
}
@@ -18,6 +18,7 @@ import com.bumble.appyx.core.plugin.Plugin
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.designsystem.showkase.getBrowserIntent
import io.element.android.libraries.di.SessionScope
@@ -28,6 +29,7 @@ class DeveloperSettingsNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val presenter: DeveloperSettingsPresenter,
private val extraDeveloperOptionsRenderer: ExtraDeveloperOptionsRenderer,
) : Node(buildContext, plugins = plugins) {
interface Callback : Plugin {
fun navigateToPushHistory()
@@ -51,6 +53,7 @@ class DeveloperSettingsNode(
onOpenShowkase = ::openShowkase,
onPushHistoryClick = callback::navigateToPushHistory,
onBackClick = callback::onDone,
extraOptions = { extraDeveloperOptionsRenderer.Render(Modifier) },
)
}
}
@@ -43,6 +43,7 @@ fun DeveloperSettingsView(
onPushHistoryClick: () -> Unit,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
extraOptions: @Composable () -> Unit = {},
) {
if (state.showLoader) {
ProgressDialog()
@@ -97,6 +98,9 @@ fun DeveloperSettingsView(
)
}
}
extraOptions()
val cache = state.cacheSize
PreferenceCategory(title = "Cache") {
ListItem(
@@ -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.preferences.impl.developer
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer
@ContributesBinding(AppScope::class)
class NoopExtraDeveloperOptionsRenderer : ExtraDeveloperOptionsRenderer {
@Composable
override fun Render(modifier: Modifier) {
// No-op
}
}
@@ -18,6 +18,7 @@ import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer
import io.element.android.features.preferences.api.PreferencesEntryPoint
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.designsystem.showkase.getBrowserIntent
@@ -28,6 +29,7 @@ class AppDeveloperSettingsNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val presenter: AppDeveloperSettingsPresenter,
private val extraDeveloperOptionsRenderer: ExtraDeveloperOptionsRenderer,
) : Node(buildContext, plugins = plugins) {
private val callback: PreferencesEntryPoint.DeveloperSettingsCallback = callback()
@@ -45,6 +47,7 @@ class AppDeveloperSettingsNode(
modifier = modifier,
onOpenShowkase = ::openShowkase,
onBackClick = callback::onDone,
extraOptions = { extraDeveloperOptionsRenderer.Render(Modifier) },
)
}
}
@@ -24,6 +24,7 @@ fun AppDeveloperSettingsPage(
onOpenShowkase: () -> Unit,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
extraOptions: @Composable () -> Unit = {},
) {
BackHandler(
onBack = onBackClick,
@@ -40,6 +41,7 @@ fun AppDeveloperSettingsPage(
onOpenShowkase = onOpenShowkase,
modifier = Modifier.padding(top = 8.dp)
)
extraOptions()
}
}