Browse Source

Merge pull request #1246 from vector-im/feature/bma/enablePolls

Feature/bma/enable polls
pull/1258/head
Benoit Marty 1 year ago committed by GitHub
parent
commit
41de288a8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      changelog.d/1241.bugfix
  2. 3
      libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlagService.kt
  3. 11
      libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt
  4. 2
      libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagService.kt
  5. 2
      libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/MutableFeatureFlagProvider.kt
  6. 9
      libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt
  7. 11
      libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt
  8. 18
      libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/di/FeatureFlagModule.kt
  9. 14
      libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagServiceTest.kt
  10. 2
      libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/FakeMutableFeatureFlagProvider.kt

1
changelog.d/1241.bugfix

@ -0,0 +1 @@
Enable polls in release build.

3
libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlagService.kt

@ -28,7 +28,8 @@ interface FeatureFlagService {
* @param feature the feature to enable or disable * @param feature the feature to enable or disable
* @param enabled true to enable the feature * @param enabled true to enable the feature
* *
* @return true if the method succeeds, ie if a RuntimeFeatureFlagProvider is registered * @return true if the method succeeds, ie if a [io.element.android.libraries.featureflag.impl.MutableFeatureFlagProvider]
* is registered
*/ */
suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean): Boolean suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean): Boolean
} }

11
libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt

@ -16,25 +16,32 @@
package io.element.android.libraries.featureflag.api package io.element.android.libraries.featureflag.api
/**
* To enable or disable a FeatureFlags, change the `defaultValue` value.
* Warning: to enable a flag for the release app, you MUST update the file
* [io.element.android.libraries.featureflag.impl.StaticFeatureFlagProvider]
*/
enum class FeatureFlags( enum class FeatureFlags(
override val key: String, override val key: String,
override val title: String, override val title: String,
override val description: String? = null, override val description: String? = null,
override val defaultValue: Boolean = true override val defaultValue: Boolean
) : Feature { ) : Feature {
LocationSharing( LocationSharing(
key = "feature.locationsharing", key = "feature.locationsharing",
title = "Allow user to share location", title = "Allow user to share location",
defaultValue = true,
), ),
Polls( Polls(
key = "feature.polls", key = "feature.polls",
title = "Polls", title = "Polls",
description = "Create poll and render poll events in the timeline", description = "Create poll and render poll events in the timeline",
defaultValue = false, defaultValue = true,
), ),
NotificationSettings( NotificationSettings(
key = "feature.notificationsettings", key = "feature.notificationsettings",
title = "Show notification settings", title = "Show notification settings",
// Do not forget to edit StaticFeatureFlagProvider when enabling the feature.
defaultValue = false, defaultValue = false,
), ),
} }

2
libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagService.kt

@ -38,7 +38,7 @@ class DefaultFeatureFlagService @Inject constructor(
} }
override suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean): Boolean { override suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean): Boolean {
return providers.filterIsInstance(RuntimeFeatureFlagProvider::class.java) return providers.filterIsInstance(MutableFeatureFlagProvider::class.java)
.sortedBy(FeatureFlagProvider::priority) .sortedBy(FeatureFlagProvider::priority)
.firstOrNull() .firstOrNull()
?.setFeatureEnabled(feature, enabled) ?.setFeatureEnabled(feature, enabled)

2
libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/RuntimeFeatureFlagProvider.kt → libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/MutableFeatureFlagProvider.kt

@ -18,6 +18,6 @@ package io.element.android.libraries.featureflag.impl
import io.element.android.libraries.featureflag.api.Feature import io.element.android.libraries.featureflag.api.Feature
interface RuntimeFeatureFlagProvider : FeatureFlagProvider { interface MutableFeatureFlagProvider : FeatureFlagProvider {
suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean) suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean)
} }

9
libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt

@ -30,12 +30,13 @@ import javax.inject.Inject
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "elementx_featureflag") private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "elementx_featureflag")
class PreferencesFeatureFlagProvider @Inject constructor(@ApplicationContext context: Context) : RuntimeFeatureFlagProvider { /**
* Note: this will be used only in the nightly and in the debug build.
*/
class PreferencesFeatureFlagProvider @Inject constructor(@ApplicationContext context: Context) : MutableFeatureFlagProvider {
private val store = context.dataStore private val store = context.dataStore
override val priority: Int override val priority = MEDIUM_PRIORITY
get() = MEDIUM_PRIORITY
override suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean) { override suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean) {
store.edit { prefs -> store.edit { prefs ->

11
libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/BuildtimeFeatureFlagProvider.kt → libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/StaticFeatureFlagProvider.kt

@ -20,17 +20,20 @@ import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.api.FeatureFlags
import javax.inject.Inject import javax.inject.Inject
class BuildtimeFeatureFlagProvider @Inject constructor() : /**
* This provider is used for release build.
* This is the place to enable or disable feature for the release build.
*/
class StaticFeatureFlagProvider @Inject constructor() :
FeatureFlagProvider { FeatureFlagProvider {
override val priority: Int override val priority = LOW_PRIORITY
get() = LOW_PRIORITY
override suspend fun isFeatureEnabled(feature: Feature): Boolean { override suspend fun isFeatureEnabled(feature: Feature): Boolean {
return if (feature is FeatureFlags) { return if (feature is FeatureFlags) {
when(feature) { when(feature) {
FeatureFlags.LocationSharing -> true FeatureFlags.LocationSharing -> true
FeatureFlags.Polls -> false FeatureFlags.Polls -> true
FeatureFlags.NotificationSettings -> false FeatureFlags.NotificationSettings -> false
} }
} else { } else {

18
libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/di/FeatureFlagModule.kt

@ -22,7 +22,7 @@ import dagger.Provides
import dagger.multibindings.ElementsIntoSet import dagger.multibindings.ElementsIntoSet
import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.featureflag.impl.BuildtimeFeatureFlagProvider import io.element.android.libraries.featureflag.impl.StaticFeatureFlagProvider
import io.element.android.libraries.featureflag.impl.FeatureFlagProvider import io.element.android.libraries.featureflag.impl.FeatureFlagProvider
import io.element.android.libraries.featureflag.impl.PreferencesFeatureFlagProvider import io.element.android.libraries.featureflag.impl.PreferencesFeatureFlagProvider
@ -35,14 +35,18 @@ object FeatureFlagModule {
@ElementsIntoSet @ElementsIntoSet
fun providesFeatureFlagProvider( fun providesFeatureFlagProvider(
buildType: BuildType, buildType: BuildType,
runtimeFeatureFlagProvider: PreferencesFeatureFlagProvider, mutableFeatureFlagProvider: PreferencesFeatureFlagProvider,
buildtimeFeatureFlagProvider: BuildtimeFeatureFlagProvider, staticFeatureFlagProvider: StaticFeatureFlagProvider,
): Set<FeatureFlagProvider> { ): Set<FeatureFlagProvider> {
val providers = HashSet<FeatureFlagProvider>() val providers = HashSet<FeatureFlagProvider>()
if (buildType == BuildType.RELEASE) { when (buildType) {
providers.add(buildtimeFeatureFlagProvider) BuildType.RELEASE -> {
} else { providers.add(staticFeatureFlagProvider)
providers.add(runtimeFeatureFlagProvider) }
BuildType.NIGHTLY,
BuildType.DEBUG -> {
providers.add(mutableFeatureFlagProvider)
}
} }
return providers return providers
} }

14
libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/DefaultFeatureFlagServiceTest.kt

@ -39,7 +39,7 @@ class DefaultFeatureFlagServiceTest {
@Test @Test
fun `given service with a runtime provider when set enabled feature is called then it returns true`() = runTest { fun `given service with a runtime provider when set enabled feature is called then it returns true`() = runTest {
val featureFlagProvider = FakeRuntimeFeatureFlagProvider(0) val featureFlagProvider = FakeMutableFeatureFlagProvider(0)
val featureFlagService = DefaultFeatureFlagService(setOf(featureFlagProvider)) val featureFlagService = DefaultFeatureFlagService(setOf(featureFlagProvider))
val result = featureFlagService.setFeatureEnabled(FeatureFlags.LocationSharing, true) val result = featureFlagService.setFeatureEnabled(FeatureFlags.LocationSharing, true)
assertThat(result).isEqualTo(true) assertThat(result).isEqualTo(true)
@ -47,7 +47,7 @@ class DefaultFeatureFlagServiceTest {
@Test @Test
fun `given service with a runtime provider and feature enabled when feature is checked then it returns the correct value`() = runTest { fun `given service with a runtime provider and feature enabled when feature is checked then it returns the correct value`() = runTest {
val featureFlagProvider = FakeRuntimeFeatureFlagProvider(0) val featureFlagProvider = FakeMutableFeatureFlagProvider(0)
val featureFlagService = DefaultFeatureFlagService(setOf(featureFlagProvider)) val featureFlagService = DefaultFeatureFlagService(setOf(featureFlagProvider))
featureFlagService.setFeatureEnabled(FeatureFlags.LocationSharing, true) featureFlagService.setFeatureEnabled(FeatureFlags.LocationSharing, true)
assertThat(featureFlagService.isFeatureEnabled(FeatureFlags.LocationSharing)).isEqualTo(true) assertThat(featureFlagService.isFeatureEnabled(FeatureFlags.LocationSharing)).isEqualTo(true)
@ -57,11 +57,11 @@ class DefaultFeatureFlagServiceTest {
@Test @Test
fun `given service with 2 runtime providers when feature is checked then it uses the priority correctly`() = runTest { fun `given service with 2 runtime providers when feature is checked then it uses the priority correctly`() = runTest {
val lowPriorityfeatureFlagProvider = FakeRuntimeFeatureFlagProvider(LOW_PRIORITY) val lowPriorityFeatureFlagProvider = FakeMutableFeatureFlagProvider(LOW_PRIORITY)
val highPriorityfeatureFlagProvider = FakeRuntimeFeatureFlagProvider(HIGH_PRIORITY) val highPriorityFeatureFlagProvider = FakeMutableFeatureFlagProvider(HIGH_PRIORITY)
val featureFlagService = DefaultFeatureFlagService(setOf(lowPriorityfeatureFlagProvider, highPriorityfeatureFlagProvider)) val featureFlagService = DefaultFeatureFlagService(setOf(lowPriorityFeatureFlagProvider, highPriorityFeatureFlagProvider))
lowPriorityfeatureFlagProvider.setFeatureEnabled(FeatureFlags.LocationSharing, false) lowPriorityFeatureFlagProvider.setFeatureEnabled(FeatureFlags.LocationSharing, false)
highPriorityfeatureFlagProvider.setFeatureEnabled(FeatureFlags.LocationSharing, true) highPriorityFeatureFlagProvider.setFeatureEnabled(FeatureFlags.LocationSharing, true)
assertThat(featureFlagService.isFeatureEnabled(FeatureFlags.LocationSharing)).isEqualTo(true) assertThat(featureFlagService.isFeatureEnabled(FeatureFlags.LocationSharing)).isEqualTo(true)
} }
} }

2
libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/FakeRuntimeFeatureFlagProvider.kt → libraries/featureflag/impl/src/test/kotlin/io/element/android/libraries/featureflag/impl/FakeMutableFeatureFlagProvider.kt

@ -18,7 +18,7 @@ package io.element.android.libraries.featureflag.impl
import io.element.android.libraries.featureflag.api.Feature import io.element.android.libraries.featureflag.api.Feature
class FakeRuntimeFeatureFlagProvider(override val priority: Int) : RuntimeFeatureFlagProvider { class FakeMutableFeatureFlagProvider(override val priority: Int) : MutableFeatureFlagProvider {
private val enabledFeatures = HashMap<String, Boolean>() private val enabledFeatures = HashMap<String, Boolean>()
Loading…
Cancel
Save