From 5b728d911b159b1cda5386fc3e80d0c370bb5f56 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 12 Aug 2026 09:30:49 +0100 Subject: [PATCH 1/2] Add hooks to allow providing additional feature flags in EX pro We modify the existing `FeaturesProvider` interface so that there can be more than one of them, and the Features provided by *all* of the instances are shown. We can then make another instance in element-android-enterprise, which exposes enterprise-only features. --- .../featureflag/api/FeaturesProvider.kt | 21 +++++++++++++++++++ .../impl/DefaultFeatureFlagService.kt | 5 +++-- ...Provider.kt => DefaultFeaturesProvider.kt} | 9 +++----- 3 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeaturesProvider.kt rename libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/{FeaturesProvider.kt => DefaultFeaturesProvider.kt} (78%) diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeaturesProvider.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeaturesProvider.kt new file mode 100644 index 0000000000..a342ccdd9b --- /dev/null +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeaturesProvider.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.featureflag.api + +/** + * Provides a list of available [Feature]s that the application supports. + * Used by [FeatureFlagService.getAvailableFeatures] to obtain a list of features + * that can be presented to the user. + * + * Multiple instances can exist within the application, and all instances are polled + * to provide features for the list. This means that additional features can be provided + * by compile-time extensions. + */ +fun interface FeaturesProvider { + fun provide(): List +} diff --git a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagService.kt b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagService.kt index 74967a574d..675cf7855c 100644 --- a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagService.kt +++ b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagService.kt @@ -14,6 +14,7 @@ import dev.zacsweers.metro.SingleIn import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.featureflag.api.Feature import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeaturesProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -22,7 +23,7 @@ import kotlinx.coroutines.flow.flowOf class DefaultFeatureFlagService( private val providers: Set<@JvmSuppressWildcards FeatureFlagProvider>, private val buildMeta: BuildMeta, - private val featuresProvider: FeaturesProvider, + private val featuresProviders: Set, ) : FeatureFlagService { override fun isFeatureEnabledFlow(feature: Feature): Flow { return if (feature.isFinished) { @@ -47,7 +48,7 @@ class DefaultFeatureFlagService( includeFinishedFeatures: Boolean, isInLabs: Boolean, ): List { - return featuresProvider.provide().filter { flag -> + return featuresProviders.flatMap { provider -> provider.provide() }.filter { flag -> (includeFinishedFeatures || !flag.isFinished) && flag.isInLabs == isInLabs } diff --git a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/FeaturesProvider.kt b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeaturesProvider.kt similarity index 78% rename from libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/FeaturesProvider.kt rename to libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeaturesProvider.kt index e24ae66783..c96a781d82 100644 --- a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/FeaturesProvider.kt +++ b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeaturesProvider.kt @@ -9,15 +9,12 @@ package io.element.android.libraries.featureflag.impl import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding +import dev.zacsweers.metro.ContributesIntoSet import io.element.android.libraries.featureflag.api.Feature import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.api.FeaturesProvider -fun interface FeaturesProvider { - fun provide(): List -} - -@ContributesBinding(AppScope::class) +@ContributesIntoSet(AppScope::class) class DefaultFeaturesProvider : FeaturesProvider { override fun provide(): List = FeatureFlags.entries } From f7d24050f8498add8c360e374044b7e94835528e Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 13 Aug 2026 17:38:59 +0100 Subject: [PATCH 2/2] fix unit test --- .../featureflag/impl/DefaultFeatureFlagServiceTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagServiceTest.kt b/libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagServiceTest.kt index 00bc687bb9..0ed6d8eafd 100644 --- a/libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagServiceTest.kt +++ b/libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagServiceTest.kt @@ -12,6 +12,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.featureflag.api.Feature +import io.element.android.libraries.featureflag.api.FeaturesProvider import io.element.android.libraries.featureflag.test.FakeFeature import io.element.android.libraries.matrix.test.core.aBuildMeta import kotlinx.coroutines.test.runTest @@ -166,5 +167,5 @@ private fun createDefaultFeatureFlagService( ) = DefaultFeatureFlagService( providers = providers, buildMeta = buildMeta, - featuresProvider = { features } + featuresProviders = setOf(FeaturesProvider { features }) )